C语言大类型指针强转为小类型指针后哪些操作属于未定义行为
C标准明确将字符类型指针(char/unsigned char/signed char)列为严格别名规则的例外,允许用这类指针遍历、修改任何对象的字节表示,基于这个前提我们逐一回答你的问题:
问题1:(char*)&big的地址偏移操作是否属于未定义行为
不属于未定义行为。uint32_t类型变量占用4个连续的内存字节,你把它的地址强转为char*后,合法的偏移范围是0 ~ sizeof(big) - 1,也就是(char*)&big + 0到(char*)&big + 3都是完全符合C标准的,只有偏移超出这个变量本身的内存范围(比如+4及以上)才会触发未定义行为。
问题2:偏移后地址的写入操作合法性,以及printf输出异常的原因
写入操作合法性
你给出的示例写入操作完全合法,不属于未定义行为。
你之前的理解有误:强转为char*后可访问的范围是整个原始变量的所有字节,不是只有第一个字节,用字符类型指针修改目标对象的单个字节是C标准明确允许的操作,你在VC编译器下正常运行不是编译器特例,是符合标准的正常表现。
printf输出ffffffff的原因
这是默认参数提升规则导致的:
如果char在你的编译环境中是有符号类型,那么你取出的0xff作为有符号char的实际值是-1,传入printf的可变参数列表时,所有小于int长度的整数类型都会被提升为int类型,-1对应的int类型十六进制表示就是0xffffffff,而%02x是按unsigned int类型解析输入的,所以最终会输出8个f而非预期的2个f。
如果要得到预期输出,可以改成两种写法:
- 强转为无符号字符指针取值:
*((unsigned char*)&big + 1) - printf参数加强制类型转换:
printf("%02x\n", (unsigned char)*((char*)&big+1));
问题3:memcpy写法的合法性,以及符合标准的实现方式
你给出的这段代码完全合法,不属于未定义行为。memcpy的底层逻辑就是按字节复制内存内容,本身不受严格别名规则限制,而且uint8_t在绝大多数符合标准的实现中就是unsigned char的别名,就算个别特殊实现不是,memcpy的标准定义也要求它的行为等价于逐字节复制,所以这段代码完全符合C标准要求,不需要额外修改。
如果要写法更严谨通用,可以把(uint8_t*)&big替换为(const void*)&big,匹配memcpy参数的标准类型定义。
内容的提问来源于stack exchange,提问作者Eric

