C++ 将具有中间转换的char*缓冲区设置为int*

C++ 将具有中间转换的char*缓冲区设置为int*,c++,c,pointers,memory,C++,C,Pointers,Memory,我无法完全理解我在这里读到的内容的后果: 简言之,这行得通吗 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 *

我无法完全理解我在这里读到的内容的后果:

简言之,这行得通吗

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;
  }

}
set4Bytes(无符号字符*缓冲区){
常数uint32_t MASK=0xffffffff;
如果((uintmax_t)缓冲区%4){//未对齐
对于(int i=0;i<4;i++){
缓冲区[i]=0xff;
} 
}else{//4字节对齐
*((uint32_t*)缓冲)=掩码;
}
}
编辑

有一个很长的讨论(在注释中,它神秘地被删除了)关于指针应该被转换到什么类型以检查对齐。主题现在已被寻址。

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

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

#include<stdint.h>
#include<stdio.h>
#include<inttypes.h>
#include<stdlib.h>

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)) );
}
#包括
#包括
#包括
#包括
int main(){
uint32_t*数据=(uint32_t*)malloc(sizeof(uint32_t)*2);
char*buf=(char*)数据;
uintpttr_t addr=(uintpttr_t)buf;
int i,j;
i=!(地址%4)?1:0;
uint32\u t x=(1如果要确保基础数据不会“改变形状”,请使用
重新解释\u cast()

正如学习者所提到的,当您将数据存储在机器内存中时,endianess成为一个因素。如果您知道数据如何正确存储在内存中(正确endianess),并且您正在专门测试其布局作为替代表示,那么您可能希望使用
reinterpret_cast()
将该内存作为特定类型进行测试,而不修改原始存储

下面,我修改了您的示例以使用
reinterpret\u cast()

void set4Bytes(无符号字符*缓冲区){
常数uint32_t MASK=0xffffffff;
如果(*重新解释强制转换(缓冲区)%4){//未对齐
对于(int i=0;i<4;i++){
缓冲区[i]=0xff;
} 
}else{//4字节对齐
*重新解释转换(缓冲)=掩码;
}
}

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

您的代码非常适合处理任何32位及以上的体系结构。字节顺序没有问题,因为您的所有源字节都是
0xFF

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

void set4Bytes(unsigned char* buffer) {
  const uint32_t MASK = 0xffffffff;
  *((uint32_t *)buffer) = MASK;
}
一些阅读资料:

  • 关于Linux内核的文档
  • 亚历山大·桑德勒的《实用》一书

  • 不,它不会在所有情况下都起作用。除了endianness(这可能是一个问题,也可能不是问题)之外,您假设
    uint32\u t
    的对齐是4。但是这个数量是实现定义的(C11草案第6.2.8节)。您可以使用
    \u Alignof
    操作符以可移植的方式获得对齐

    其次,
    buffer
    指向的位置的有效类型(同上,第6.5节)可能与
    uint32\u t
    不兼容(例如,如果
    buffer
    指向一个
    无符号字符
    数组)。在这种情况下,一旦尝试读取数组本身或其他类型的指针,就会违反严格的别名规则

    假设指针实际指向一个
    无符号字符数组
    ,下面的代码将起作用

    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;
      }
    }
    
    typedef union{unsigned char chr[sizeof(uint32_t)];uint32_t;}conv_t;
    void set4Bytes(无符号字符*缓冲区){
    常数uint32_t MASK=0xffffffffU;
    如果((uintpttr_t)缓冲区%u对齐(uint32_t)){//未对齐
    对于(大小i=0;iu32=掩模;
    }
    }
    
    除了这里已经提到的endian问题之外:

    CHAR\u BIT
    -还应考虑每个
    CHAR
    的位数


    在大多数平台上,它是8,其中
    for(int i=0;iUhm,我认为您误解了if语句的要点,即检查指针是否对齐4字节(如果我理解正确,则检查缓冲区的内容)@Antonio原始代码已从
    无符号int
    更改为
    uintpttr\t
    ;因此不完全正确。新代码使用静态强制转换(C语法)从指针到指针,所以现在您只使用不同的语法执行与我的代码相同的操作。@Antonio这是真的,我不明白您试图实现什么,因为如果调用
    set4bytes()<代码> > <代码> SET4BYTES>()/CUT>,它不会采用同一分支吗?问题被标记为C和C++,并且没有重新解释。C@CashCow在C语言中,所有类型转换在功能上都等价于
    静态类型转换()
    重新解释类型转换()
    。等效的C语法是
    *((unsigned int*))缓冲区)
    这会违反严格的别名规则,从而导致未定义的行为。类型为
    char
    的对象可能无法通过类型为
    uint32\u t
    的左值访问其值。在C++11中,相关部分为3.10/10。谢谢。我修复了该违规行为。这是一个非常有趣的发现。对于C++98,基本上对齐与sizeof…解耦,因此t这里没有可移植的解决方案,对吗?我想是的,除非有另一种可移植的方式来获得类型对齐。无论如何,我猜对象对齐了我
    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;
      }
    }