设置char *的缓冲区,中间转换为int *

我无法完全理解我在这里阅读的内容的后果: 将一个int指针转换为char ptr,反之亦然

总之,这会有用吗?

set4Bytes(unsigned char* buffer) { const uint32_t MASK = 0xffffffff; if ((uintmax_t)buffer % 4) {//misaligned for (int i = 0; i < 4; i++) { buffer[i] = 0xff; } } else {//4-byte alignment *((uint32_t*) buffer) = MASK; } } 

编辑
有一个长时间的讨论(在评论中,神秘地删除了)关于指针应该被铸造到什么类型以检查对齐。 现在讨论这个问题 。

如果要在所有4个字节中填充相同的值,则此转换是安全的。 如果byte order重要,则此转换不安全。 因为当您使用整数一次填充4个字节时,它将填充4 Bytes但顺序取决于字节顺序 。

此代码可能对您有所帮助。 它显示了通过一次为其内容分配一个字节来构建32位数字,从而强制不对齐。 它编译并在我的机器上工作。

 #include #include #include #include int main () { uint32_t *data = (uint32_t*)malloc(sizeof(uint32_t)*2); char *buf = (char*)data; uintptr_t addr = (uintptr_t)buf; int i,j; i = !(addr%4) ? 1 : 0; uint32_t x = (1<<6)-1; for( j=0;j<4;j++ ) buf[i+j] = ((char*)&x)[j]; printf("%" PRIu32 "\n",*((uint32_t*) (addr+i)) ); } 

正如@Learner所提到的,必须遵守字节顺序。 上面的代码不可移植,并且会在大端机器上中断。

请注意,我的编译器在尝试将char *转换为unsigned int时抛出错误“从'char *'转换为'unsigned int'会丢失precision [-fpermissive]”,如原始post中所做的那样。 这篇文章解释了应该使用uintptr_t。

不,它不会在每种情况下都有效。 除了可能存在或可能不存在问题的字节序,您假设uint32_t的对齐为4.但此数量是实现定义的(C11草案N1570第6.2.8节)。 您可以使用_Alignof运算符以便携方式获取对齐方式。

其次, buffer指向的有效类型( 同上,第6.5节)可能与uint32_t不兼容(例如,如果buffer指向unsigned char数组)。 在这种情况下,一旦尝试读取数组本身或通过不同类型的指针,就会破坏严格的别名规则。

假设指针实际指向unsigned char数组,以下代码将起作用

 typedef union { unsigned char chr[sizeof(uint32_t)]; uint32_t u32; } conv_t; void set4Bytes(unsigned char* buffer) { const uint32_t MASK = 0xffffffffU; if ((uintptr_t)buffer % _Alignof(uint32_t)) {// misaligned for (size_t i = 0; i < sizeof(uint32_t); i++) { buffer[i] = 0xffU; } } else { // correct alignment conv_t *cnv = (conv_t *) buffer; cnv->u32 = MASK; } } 

除了已经在这里提到的endian问题:

CHAR_BIT – 每个char的位数 – 也应该考虑。

在大多数平台上它是8,其中for (int i=0; i<4; i++)应该可以正常工作。

更安全的方法是for (int i=0; i

或者,您可以包含并使用for (int i=0; i<32/CHAR_BIT; i++)

如果要确保基础数据不“改变形状”,请使用reinterpret_cast<>()

正如Learner所提到的,当您将数据存储在机器内存中时, endianess就成了一个因素。 如果您知道数据如何在内存中正确存储(正确的字节顺序)并且您专门测试其布局作为替代表示,那么您可能希望使用reinterpret_cast<>()来测试该内存,作为特定类型,而无需修改原始存储。

下面,我修改了你的例子以使用reinterpret_cast<>()

 void set4Bytes(unsigned char* buffer) { const uint32_t MASK = 0xffffffff; if (*reinterpret_cast(buffer) % 4) {//misaligned for (int i = 0; i < 4; i++) { buffer[i] = 0xff; } } else {//4-byte alignment *reinterpret_cast(buffer) = MASK; } } 

还应该注意,您的函数似乎将缓冲区(32字节的连续内存)设置为0xFFFFFFFF,无论它采用哪个分支。

您的代码非常适合使用32位及以上的任何架构。 字节排序没有问题,因为所有源字节都是0xFF

在x86或x64机器上,处理最终未对齐RAM访问所需的额外工作由CPU管理,对程序员是透明的(自Pentium II以来),每次访问都会有一些性能成本。 因此,如果您只是将缓冲区的前四个字节设置为几次,则可以简化您的function:

 void set4Bytes(unsigned char* buffer) { const uint32_t MASK = 0xffffffff; *((uint32_t *)buffer) = MASK; } 

一些读物:

  1. 关于UNALIGNED MEMORY ACCESSES的 Linux内核文档
  2. 英特尔架构优化手册,第3.4节
  3. IPF,x86和x64上的Windows数据对齐
  4. Alexander Sandler实用的“ 对齐与未对齐的内存访问 ”