相关疑难解决方法(0)

C和C++中联合的目的

我早先使用过工会; 今天,当我读到这篇文章并开始知道这段代码时,我感到震惊

union ARGB
{
    uint32_t colour;

    struct componentsTag
    {
        uint8_t b;
        uint8_t g;
        uint8_t r;
        uint8_t a;
    } components;

} pixel;

pixel.colour = 0xff040201;  // ARGB::colour is the active member from now on

// somewhere down the line, without any edit to pixel

if(pixel.components.a)      // accessing the non-active member ARGB::components
Run Code Online (Sandbox Code Playgroud)

实际上是未定义的行为即从工会成员读取而不是最近编写的那个导致未定义的行为.如果这不是工会的预期用途,那是什么?有人可以详细解释一下吗?

更新:

事后我想澄清一些事情.

  • 这个问题的答案与C和C++不一样; 我无知的年轻自我将其标记为C和C++.
  • 在仔细研究了C++ 11的标准后,我无法确切地说它调用了访问/检查非活动的union成员是未定义/未指定/实现定义的.我能找到的只是§9.5/ 1:

    如果标准布局联合包含多个共享公共初始序列的标准布局结构,并且如果此标准布局联合类型的对象包含其中一个标准布局结构,则允许检查任何标准布局结构的公共初始序列.标准布局结构成员.§9.2/ 19:如果相应的成员具有布局兼容类型且两个成员都不是位字段,或者两者都是具有相同宽度的位字段,则一个或多个初始序列的两个标准布局结构共享一个公共初始序列成员.

  • 在C中,(C99 TC3 - DR 283以后)这样做是合法的(感谢Pascal Cuoq提出这个问题).但是,如果读取的值对于读取的类型无效(所谓的"陷阱表示"),尝试执行此操作仍会导致未定义的行为.否则,读取的值是实现定义的.
  • C89/90在未指明的行为(附件J)中称之为,而K&R的书称其实施已定义.来自K&R的报价:

    这是联合的目的 - 一个可以合法地保存几种类型中的任何一种的变量.[...]只要用法一致:检索到的类型必须是最近存储的类型.程序员有责任跟踪当前存储在联合中的类型; 如果将某些内容存储为一种类型并将其提取为另一种类型,则结果将依赖于实现. …

c c++ unions type-punning

237
推荐指数
9
解决办法
10万
查看次数

访问非活动的union成员和未定义的行为?

我的印象是访问union除最后一个成员之外的成员是UB,但我似乎无法找到一个可靠的参考(除了声称它是UB但没有标准支持的答案).

那么,这是不确定的行为?

c++ undefined-behavior unions language-lawyer

114
推荐指数
4
解决办法
2万
查看次数

是否可以在Rust中编写Quake的快速InvSqrt()函数?

这只是为了满足我自己的好奇心。

是否有此实现:

float InvSqrt (float x)
{
   float xhalf = 0.5f*x;
   int i = *(int*)&x;
   i = 0x5f3759df - (i>>1);
   x = *(float*)&i;
   x = x*(1.5f - xhalf*x*x);
   return x;
}
Run Code Online (Sandbox Code Playgroud)

在Rust中?如果存在,则发布代码。

我尝试过但失败了。我不知道如何使用整数格式编码浮点数。这是我的尝试:

fn main() {
    println!("Hello, world!");
    println!("sqrt1: {}, ",sqrt2(100f64));
}

fn sqrt1(x: f64) -> f64 {
    x.sqrt()
}

fn sqrt2(x: f64) -> f64 {
    let mut x = x;
    let xhalf = 0.5*x;
    let mut i = x as i64;
    println!("sqrt1: {}, ", i);

    i = 0x5f375a86 as …
Run Code Online (Sandbox Code Playgroud)

floating-point sqrt type-punning rust

62
推荐指数
3
解决办法
5420
查看次数

为什么优化会破坏此功能?

我们最近在大学里开了一个关于多种语言编程特色的讲座.

讲师写下了以下功能:

inline u64 Swap_64(u64 x)
{
    u64 tmp;
    (*(u32*)&tmp)       = Swap_32(*(((u32*)&x)+1));
    (*(((u32*)&tmp)+1)) = Swap_32(*(u32*) &x);

    return tmp;
}
Run Code Online (Sandbox Code Playgroud)

虽然我完全理解这在可读性方面也是非常差的风格,但他的主要观点是这部分代码在生产代码中运行良好,直到它们实现了高优化级别.然后,代码将什么都不做.

他说,变量的所有赋值tmp都将由编译器优化.但为什么会这样呢?

我知道有些情况下变量需要声明为volatile,这样编译器就不会触及它们,即使他认为它们永远不会被读或写,但我不知道为什么会发生这种情况.

c c++ optimization endianness strict-aliasing

49
推荐指数
3
解决办法
4343
查看次数

如何制作便携式isnan/isinf功能

我一直在使用isinf,isnan在Linux平台上运行完美的功能.但是这在OS-X上不起作用,所以我决定使用std::isinf std::isnan哪种适用于Linux和OS-X.

但英特尔编译器无法识别它,我猜它是英特尔编译器中的一个错误,根据http://software.intel.com/en-us/forums/showthread.php?t=64188

所以,现在我只是想避免麻烦和定义自己的isinf,isnan执行.

有谁知道如何做到这一点?

编辑:

我最终在我的源代码中进行了制作isinf/ isnan工作

#include <iostream>
#include <cmath>

#ifdef __INTEL_COMPILER
#include <mathimf.h>
#endif

int isnan_local(double x) { 
#ifdef __INTEL_COMPILER
  return isnan(x);
#else
  return std::isnan(x);
#endif
}

int isinf_local(double x) { 
#ifdef __INTEL_COMPILER
  return isinf(x);
#else
  return std::isinf(x);
#endif
}


int myChk(double a){
  std::cerr<<"val is: "<<a <<"\t";
  if(isnan_local(a))
    std::cerr<<"program says isnan";
  if(isinf_local(a))
    std::cerr<<"program says isinf";
  std::cerr<<"\n";
  return 0;
}

int main(){
  double a …
Run Code Online (Sandbox Code Playgroud)

c c++ math function

37
推荐指数
6
解决办法
4万
查看次数

多字符恒定警告

为什么这是一个警告?我认为在很多情况下使用multi-char int常量而不是"无意义"数字或者使用相同值定义const变量更为明确.解析wave/tiff /其他文件类型时,可以更清楚地将读取值与某些"EVAW","数据"等进行比较,而不是相应的值.

示例代码:

int waveHeader = 'EVAW';
Run Code Online (Sandbox Code Playgroud)

为什么这会发出警告?

c c++ portability casting compiler-warnings

35
推荐指数
5
解决办法
8万
查看次数

最有效的符合标准的方法,将int重新解释为float

假设我有floatIEEE 754 binary32的保证.给定一个与存储的有效浮点相对应的位模式std::uint32_t,如何float以最有效的标准兼容方式将其重新解释为?

float reinterpret_as_float(std::uint32_t ui) {
   return /* apply sorcery to ui */;
}
Run Code Online (Sandbox Code Playgroud)

我有几种方法,我知道/怀疑/假设有一些问题:

  1. 通过reinterpret_cast,

    float reinterpret_as_float(std::uint32_t ui) {
        return reinterpret_cast<float&>(ui);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    或者等价的

    float reinterpret_as_float(std::uint32_t ui) {
        return *reinterpret_cast<float*>(&ui);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    哪个遭受别名问题.

  2. 通过union,

    float reinterpret_as_float(std::uint32_t ui) {
        union {
            std::uint32_t ui;
            float f;
        } u = {ui};
        return u.f;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这实际上并不合法,因为它只允许从最近写的成员读取.然而,似乎有些编译器(gcc)允许这样做.

  3. 通过std::memcpy,

    float reinterpret_as_float(std::uint32_t ui) {
        float f;
        std::memcpy(&f, &ui, 4);
        return f;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    哪种AFAIK是合法的,但复制单个单词的函数调用似乎很浪费,尽管它可能会被优化掉.

  4. 通过reinterpret_cast …

c++ standards-compliance type-conversion language-lawyer c++11

31
推荐指数
1
解决办法
4324
查看次数

什么是将一个浮点数类型化为int的正确方法,反之亦然?

下面的代码通过一些位攻击执行快速反平方根操作.该算法可能是由Silicon Graphics在1990年代早期开发的,它也出现在Quake 3中. 更多信息

但是我从GCC C++编译器收到以下警告:解除引用类型惩罚指针将破坏严格别名规则

我应该使用static_cast,reinterpret_cast还是dynamic_cast在这种情况下使用?

float InverseSquareRoot(float x)
{
    float xhalf = 0.5f*x;
    int32_t i = *(int32_t*)&x;
    i = 0x5f3759df - (i>>1);
    x = *(float*)&i;
    x = x*(1.5f - xhalf*x*x);
    return x;
}
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing gcc-warning undefined-behavior type-punning

24
推荐指数
4
解决办法
6830
查看次数

读取与活动变体类型相同的联合体的另一个变体成员是否会导致 UB?

union A{
  int a;
  int b;
};
int main(){
  A u = {.a = 0};
  int r = u.b; // #1 Is this UB?
}
Run Code Online (Sandbox Code Playgroud)

[class.union] 说

在联合中,如果非静态数据成员的名称引用其生命周期已开始且尚未结束的对象 ([basic.life]),则该非静态数据成员处于活动状态。联合类型对象的最多一个非静态数据成员在任一时刻可以是活动的,即任一时刻联合体中最多可以存储一个非静态数据成员的值。

在此示例中,仅A::a处于活动状态,然后 [basic.life] p7 表示

如果出现以下情况,则程序具有未定义的行为:

  • 左值用于访问对象,或者

#1尝试访问生命周期尚未开始的对象。此访问是否会导致 UB,如果是,此要求是否过于严格?

顺便说一句,C 标准在此示例中是否提出了相同的要求?或者说,在这种情况下,C 有更宽松的要求吗?

更新

C标准中,我找到了一个注释,上面写着

如果用于读取联合对象内容的成员与最后用于在对象中存储值的成员不同,则该值的对象表示形式的适当部分将被重新解释为新类型中的对象表示形式,如下所述6.2.6(有时称为类型双关的过程)。这可能是非值表示。

这意味着它在 C 中是允许的。但是,https://eel.is/c++draft/diff.iso

除了上面列出的差异之外,子条款 [diff.iso] 按本文档的章节列出了 C++ 和 ISO C 之间的差异。

没有指出差异。

c c++ language-lawyer

21
推荐指数
1
解决办法
388
查看次数

什么比std :: pow更快?

我的程序在该std::pow(double,int)函数中花费了90%的CPU时间.准确性不是这里的主要关注点,所以我想知道是否有更快的替代品.我想要尝试的一件事是铸造浮动,执行操作然后再加倍(尚未尝试过); 我担心这不是一种提高性能的可移植方式(不管大多数CPU本质上都是双重操作吗?)

干杯

c++ performance

18
推荐指数
3
解决办法
2万
查看次数