小编dig*_*ale的帖子

C++的严格别名规则 - 'char'别名豁免是否为双向街道?

就在几周前,我了解到C++标准有一个严格的别名规则.基本上,我曾经问过一个关于移位的问题 - 而不是一次一个地移动每个字节,以最大化性能我想加载我的处理器的本机寄存器(分别为32或64位)并执行4/8的移位所有字节都在一条指令中.

这是我想避免的代码:

unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };

for (int i = 0; i < 3; ++i)
{
  buffer[i] <<= 4; 
  buffer[i] |= (buffer[i + 1] >> 4);
}
buffer[3] <<= 4;
Run Code Online (Sandbox Code Playgroud)

相反,我想使用类似的东西:

unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
unsigned int *p = (unsigned int*)buffer; // unsigned int is 32 bit on my platform
*p <<= 4;
Run Code Online (Sandbox Code Playgroud)

有人在评论中提到我提出的解决方案违反了C++别名规则(因为p是类型int*,缓冲区是类型的char*,我正在取消引用p来执行移位.(请忽略对齐和字节顺序的可能问题 - 我处理那个片段之外的那些人)我很惊讶地了解他严格别名规则,因为我经常对缓冲区中的数据进行操作,将其从一种类型转换为另一种类型并且从未出现任何问题.进一步调查显示我使用的编译器(MSVC) )没有强制执行严格的别名规则,因为我只是在业余时间开发gcc/g ++作为业余爱好,我可能还没有遇到过这个问题.

那么我问了一个关于严格别名规则和C++的Placement new运算符的问题:

IsoCpp.org提供有关放置新的常见问题解答,它们提供以下代码示例:

#include …
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing

15
推荐指数
1
解决办法
790
查看次数

reinterpret_cast <char*>是reinterpret_cast的唯一有效用途吗?

我最近了解到C++标准包含"严格别名规则",禁止通过不同类型的变量引用相同的内存位置.

但是,该标准允许char类型合法地别名为任何其他类型.这是否意味着reinterpret_cast可以合法地仅用于投射到类型char *char &

我认为严格别名允许在继承层次结构中的类型之间进行转换,但我认为这些情况会倾向于使用dynamic_cast <>?

谢谢

c++ strict-aliasing

8
推荐指数
3
解决办法
1131
查看次数

Visual C++是否支持"严格别名"?

我最近惊讶地发现C和C++语言标准有一个"严格别名"规则.实质上,该规则禁止不同类型的变量引用相同的内存位置.

举个例子:

char buffer[4] = { 0x55, 0x66, 0x77, 0x88 };
int32 *p = (int32*)&buffer[0]; // illegal because buffer[0] and *p are different types
Run Code Online (Sandbox Code Playgroud)

我与之交互的大多数专业C++开发人员都不熟悉这条规则.根据我的研究,它似乎主要影响GCC/G ++/CLANG用户.Visual C++是否支持启用/禁用此规则?如果是这样,那么一个人怎么做?

谢谢

strict-aliasing visual-c++

7
推荐指数
1
解决办法
1628
查看次数

以32/64位数量有效地对字节进行位移?

为简单起见,假设我使用的是32位小端处理器并声明了以下4字节缓冲区:

unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
Run Code Online (Sandbox Code Playgroud)

假设我的目标是逐位左移将缓冲区中的每个字节移位4位.也就是说,我想将缓冲区值转换为: { 0xbc, 0xde, 0xf4, 0x60 }.要执行这样的转换,可以编写如下代码:

for (int i = 0; i < 3; ++i)
{
  buffer[i] <<= 4; 
  buffer[i] |= (buffer[i + 1] >> 4);
}
buffer[3] <<= 4;
Run Code Online (Sandbox Code Playgroud)

虽然这有效,但我更倾向于使用处理器的本机32位寄存器同时移位所有4个字节:

unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
unsigned int *p = (unsigned int*)buffer; // unsigned int is 32 bit on my platform
*p <<= 4;
Run Code Online (Sandbox Code Playgroud)

上面的片段成功地执行了一次转换,但不是我正在寻找的方式.看来,因为我将缓冲区转换为unsigned int,所以寄存器被加载(little-endian)并带有值0x46efcdab(而不是0xabcdef46).因此,执行4位左移0xb0dafc6e而不是 …

c bit-manipulation bit-shift

4
推荐指数
1
解决办法
169
查看次数

严格的别名规则和新的安置

IsoCpp.org提供有关新展示位置的常见问题解答:

他们提供的例子是:

#include <new>        // Must #include this to use "placement new"
#include "Fred.h"     // Declaration of class Fred
void someCode()
{
  char memory[sizeof(Fred)];     // Line #1
  void* place = memory;          // Line #2
  Fred* f = new(place) Fred();   // Line #3 (see "DANGER" below)
  // The pointers f and place will be equal
  // ...
}
Run Code Online (Sandbox Code Playgroud)

不会上面的代码违反因为C++的严格别名规则placememory是不同的类型,但引用相同的存储器的地址?

(我知道类型的指针char可以别名任何其他类型,但是在这里我们似乎有一个void*别名a char*,这是我不理解的?)

我怀疑大多数内存分配器也会以类似的方式违反严格的别名规则.使用贴图新内容时遵循严格别名规则的正确方法是什么?

谢谢

c++ strict-aliasing placement-new

2
推荐指数
2
解决办法
409
查看次数