标签: strict-aliasing

什么是严格别名规则?

当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?

c strict-aliasing undefined-behavior type-punning

778
推荐指数
10
解决办法
19万
查看次数

使用此指针会在热循环中导致奇怪的去优化

我最近遇到了一个奇怪的去优化(或者错过了优化机会).

考虑此函数可以有效地将3位整数数组解包为8位整数.它在每次循环迭代中解包16个int:

void unpack3bit(uint8_t* target, char* source, int size) {
   while(size > 0){
      uint64_t t = *reinterpret_cast<uint64_t*>(source);
      target[0] = t & 0x7;
      target[1] = (t >> 3) & 0x7;
      target[2] = (t >> 6) & 0x7;
      target[3] = (t >> 9) & 0x7;
      target[4] = (t >> 12) & 0x7;
      target[5] = (t >> 15) & 0x7;
      target[6] = (t >> 18) & 0x7;
      target[7] = (t >> 21) & 0x7;
      target[8] = (t >> 24) & 0x7;
      target[9] = …
Run Code Online (Sandbox Code Playgroud)

c++ optimization strict-aliasing compiler-optimization c++11

117
推荐指数
3
解决办法
5163
查看次数

在C++中,我是否应该费心缓存变量,还是让编译器进行优化?(混叠)

请考虑以下代码(p属于类型unsigned char*bitmap->width属于某种整数类型,具体哪个是未知的,取决于我们正在使用的某个外部库的版本):

for (unsigned x = 0;  x < static_cast<unsigned>(bitmap->width);  ++x)
{
    *p++ = 0xAA;
    *p++ = 0xBB;
    *p++ = 0xCC;
}
Run Code Online (Sandbox Code Playgroud)

值得优化它[...]

可能存在这样一种情况,即通过编写可以产生更有效的结果:

unsigned width(static_cast<unsigned>(bitmap->width));
for (unsigned x = 0;  x < width;  ++x)
{
    *p++ = 0xAA;
    *p++ = 0xBB;
    *p++ = 0xCC;
}
Run Code Online (Sandbox Code Playgroud)

...或者编译器优化是否微不足道?

您认为什么是"更好"的代码?

编辑(Ike)的注意事项:对于那些对三角形文本感到疑惑的人来说,原来的问题,如同措辞一样,非常接近于偏离主题的领域,并且尽管有积极的反馈,但非常接近于被关闭.这些已经被打乱了.但是,请不要惩罚那些解决这些问题的受影响部分的回答者.

c++ optimization performance caching strict-aliasing

114
推荐指数
9
解决办法
7276
查看次数

假设指向同一变量的两个指针是非法的/UB,为什么 C 编译器不能优化更改 const 指针的值?

最近我偶然发现了 Rust 和 C 之间的比较,它们使用以下代码:

bool f(int* a, const int* b) {
  *a = 2;
  int ret = *b;
  *a = 3;
  return ret != 0;
}
Run Code Online (Sandbox Code Playgroud)

在 Rust(相同的代码,但使用 Rust 语法)中,它生成以下汇编代码:

    cmp      dword ptr [rsi], 0 
    mov      dword ptr [rdi], 3 
    setne al                    
    ret
Run Code Online (Sandbox Code Playgroud)

使用 gcc 时,它会产生以下结果:

   mov      DWORD PTR [rdi], 2   
   mov      eax, DWORD PTR [rsi]
   mov      DWORD PTR [rdi], 3        
   test     eax, eax                  
   setne al                           
   ret
Run Code Online (Sandbox Code Playgroud)

文本声称 C 函数不能优化第一行,因为ab可能指向相同的数字。在 Rust 中这是不允许的,因此编译器可以将其优化掉。

现在我的问题:

该函数采用一个const …

c strict-aliasing undefined-behavior rust

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

char*和std :: uint8_t之间的reinterpret_cast* - 安全吗?

现在我们有时必须使用二进制数据.在C++中,我们使用字节序列,因为开头char是我们的构建块.定义为sizeof1,它是字节.char默认情况下,所有库I/O函数都使用.一切都很好,但总是有一点担心,有点奇怪,一些人的错误 - 一个字节中的位数是实现定义的.

所以在C99中,决定引入几个typedef让开发人员轻松表达自己的固定宽度整数类型.当然可选,因为我们从不想伤害便携性.其中uint8_t,迁移到C++ 11中std::uint8_t,固定宽度的8位无符号整数类型,对于真正想要使用8位字节的人来说是完美的选择.

因此,开发人员接受了新工具并开始构建库,这些库明确表示它们接受8位字节序列std::uint8_t*,std::vector<std::uint8_t>或者其他方式.

但是,或许经过深思熟虑,标准化委员会决定不要求实施,std::char_traits<std::uint8_t>因此禁止开发人员轻松,便携地实例化,比如说,std::basic_fstream<std::uint8_t>并轻松读取std::uint8_t二进制数据.或许,我们中的一些人不关心字节中的位数并且对它感到满意.

但遗憾的是,两个世界相互冲突,有时您必须将数据作为char*并将其传递给期望的库std::uint8_t*.但是等等,你说,是不是char变量位并std::uint8_t固定为8?它会导致数据丢失吗?

嗯,这里有一个有趣的标准.的char定义为保持正好一个字节和字节是内存的最低可寻址的块,所以用比特宽度比的较小不能有一个类型char.接下来,它被定义为能够保存UTF-8代码单元.这给了我们最小--8位.所以现在我们有一个typedef,它要求是8位宽,并且是一个至少8位宽的类型.但有其他选择吗?是的,unsigned char.请记住,签名char是实现定义的.还有其他任何一种 谢天谢地,没有.所有其他整数类型都需要超出8位的范围.

最后,std::uint8_t是可选的,这意味着如果未定义使用此类型的库将无法编译.但如果它编译呢?我可以非常自信地说,这意味着我们在8位字节的平台上CHAR_BIT == 8.

一旦我们有这方面的知识,我们已经8位字节,这std::uint8_t是实现为char或者unsigned char,我们可以假设,我们可以做reinterpret_castchar*std::uint8_t*,反之亦然?它是便携式的吗?

这是我的Standardese阅读技巧让我失望的地方.我读了关于安全派生的指针([basic.stc.dynamic.safety]),据我所知,以下内容:

std::uint8_t* buffer = /* ... */ ;
char* buffer2 …
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing language-lawyer c++11 uint8t

58
推荐指数
2
解决办法
1万
查看次数

违反C中的严格别名,即使没有任何演员?

怎么能*iu.i这个代码打印不同的数字,即使i被定义为int *i = &u.i;?我只能假设我在这里触发UB,但我看不清楚到底是怎么回事.

(如果我选择'C'作为语言,ideone demo会复制.但正如@ 2501指出的那样,如果'C99严格'是语言,那就不行了.但话又说回来,我得到了问题gcc-5.3.0 -std=c99!)

// gcc       -fstrict-aliasing -std=c99   -O2
union
{   
    int i;
    short s;
} u;

int     * i = &u.i;
short   * s = &u.s;

int main()
{   
    *i  = 2;
    *s  = 100;

    printf(" *i = %d\n",  *i); // prints 2
    printf("u.i = %d\n", u.i); // prints 100

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

(gcc 5.3.0,with -fstrict-aliasing -std=c99 -O2,with with -std=c11 …

c strict-aliasing

58
推荐指数
6
解决办法
3058
查看次数

"解除引用类型惩罚指针将破坏严格别名规则"警告

我使用一个代码,我将枚举*转换为int*.像这样的东西:

enum foo { ... }
...
foo foobar;
int *pi = reinterpret_cast<int*>(&foobar);
Run Code Online (Sandbox Code Playgroud)

在编译代码(g ++ 4.1.2)时,我收到以下警告消息:

dereferencing type-punned pointer will break strict-aliasing rules
Run Code Online (Sandbox Code Playgroud)

我用Google搜索了这条消息,发现只有在严格的别名优化打开时才会发生这种情况.我有以下问题:

  • 如果我留下带有此警告的代码,它是否会生成可能错误的代码?
  • 有没有办法解决这个问题?
  • 如果没有,是否可以从源文件内部关闭严格别名(因为我不想为所有源文件关闭它,我不想为此源文件制作单独的Makefile规则)?

是的,我实际上需要这种别名.

c++ warnings strict-aliasing

53
推荐指数
4
解决办法
5万
查看次数

std :: memcpy是否在不同的可复制类型之间是未定义的行为?

我一直在std::memcpy用来规避严格的混叠很长一段时间.

例如,检查a float,像这样:

float f = ...;
uint32_t i;
static_assert(sizeof(f)==sizeof(i));
std::memcpy(&i, &f, sizeof(i));
// use i to extract f's sign, exponent & significand
Run Code Online (Sandbox Code Playgroud)

但是,这次,我检查了标准,我还没有找到任何可以验证这一点的东西.我所发现的是这个:

对于平凡可复制类型T的任何对象(可能重叠的子对象除外),无论对象是否保持类型T的有效值,组成对象的基础字节([intro.memory])都可以复制到char,unsigned char或std :: byte([cstddef.syn])数组.40如果将该数组的内容复制回对象,则该对象应随后保持其原始值.[例如:

#define N sizeof(T)
char buf[N];
T obj;                          // obj initialized to its original value
std::memcpy(buf, &obj, N);      // between these two calls to std?::?memcpy, obj might be modified
std::memcpy(&obj, buf, N);      // at this point, each subobject of obj of scalar …
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing undefined-behavior language-lawyer c++17

52
推荐指数
3
解决办法
2898
查看次数

gcc,严格别名和恐怖故事

gcc-strict-aliasing-and-casting-through-a-union中,我问是否有人遇到过通过指针进行联合惩罚的问题.到目前为止,答案似乎是否定的.

这个问题是广泛的:你有任何关于gcc和严格走样恐怖故事?

背景:引用AndreyT在c99-strict-aliasing-rules-in-c-gcc中的答案:

"严格的别名规则植根于自[标准化]时代开始以来C和C++中存在的标准部分.禁止通过另一种类型的左值访问一种类型的对象的条款存在于C89/90中(6.3 )以及C++ 98(3.10/15)......并非所有编译器都希望(或敢于)强制执行或依赖它.

好吧,gcc现在敢于用它的-fstrict-aliasing开关来做到这一点.这引起了一些问题.例如,请参阅有关Mysql错误的优秀文章 http://davmac.wordpress.com/2009/10/,以及http://cellperformance.beyond3d.com/articles/2006/06/understanding中同样出色的讨论.-strict-aliasing.html.

其他一些不太相关的链接:

重复一遍,你有自己的恐怖故事吗?当然,没有表示的问题-Wstrict-aliasing是优选的.其他C编译器也很受欢迎.

6月2日补充:迈克尔伯尔的答案中的第一个链接,确实有资格作为恐怖故事,可能有点过时(从2003年开始).我做了一个快速测试,但问题显然已经消失了.

资源:

#include <string.h>
struct iw_event {               /* dummy! */
    int len;
};
char *iwe_stream_add_event(
    char *stream,               /* Stream of events */
    char *ends,                 /* End of stream */
    struct iw_event *iwe,       /* Payload */
    int event_len)              /* Real size of payload …
Run Code Online (Sandbox Code Playgroud)

c gcc strict-aliasing

51
推荐指数
4
解决办法
3万
查看次数

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

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

讲师写下了以下功能:

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
查看次数