[英]Confusion about pointer casts in c
char* p = (char*) malloc(8 * sizeof(char));
strcpy(p, "fungus");
for (int i = 0; i < strlen(p); i++) {
printf("%c", p[i]);
}
char* p2 = (char*) malloc(4 * sizeof(char));
*p2 = *(uint16_t*) p;
printf("\nPointer: %c\n", p2[1]);
所以我创建了一个 char* p 来存储字符串“fungus”。 据我了解,如果我将 p 类型转换为 uint16_t* 并取消引用它,则返回的值应该是 p 指向的前 2 个字节。 因此,p2[1] 应该是“u”,因为“u”是字符串“fungus”中的第二个字节。 但是,当我运行我的程序时,情况并非如此。 我也尝试打印 p[0] + 1,但这只是输出“g”。 我的逻辑有错误吗?
据我了解,如果我将 p 类型转换为 uint16_t* 并取消引用它,则返回的值应该是 p 指向的前 2 个字节。
这是不正确的,至少有两个原因。
One, a pointer to a char
might not have the alignment required for a uint16_t
, and then the conversion to uint16_t
is not defined by the C standard, per C 2018 6.3.2.3 7:
... 如果结果指针未正确对齐 70) 用于引用类型,则行为未定义...
这不适用于问题中的示例代码,因为char *
是从malloc
分配的,并且malloc
始终返回适合任何基本类型对齐的地址。 但是,它可能适用于以其他方式创建的char *
(包括向p
添加偏移量,例如尝试将p+1
转换为uint16_t *
)。
Two, accessing objects defined as char
(including those created by writing char
values to memory allocated with malloc
) as if they were uint16_t
violates the aliasing rules in C 2018 6.5 7. It is possible a C implementation might reinterpret the two char
as a uint16_t
,但编译器的优化也有可能将未定义的行为转换为其他行为。
*p2 = *(uint16_t*) p;
此代码是对单个 char *p2
的赋值,即p2[0]
,而不管右侧可能是 16 位值。 它不触及p2[1]
。
如果*(uint16_t*) p;
确实将字符串的两个 8 位字节重新解释为uint16_t
,然后它将产生一些 16 位值,然后分配给单个char
*p2
。 如果char
是无符号的,则该值的低八位将存储为p2[0]
,而p2[1]
保持不变。 如果已签名,则将执行实现定义的转换,并将结果(如果未发生陷阱)分配给p2[0]
,同样保持p2[1]
不变。
然后printf("\nPointer: %c\n", p2[1]);
尝试打印尚未初始化的值,因为p2[1]
中没有任何值。
您可以尝试更改*p2 = *(uint16_t*) p;
到* (uint16_t *) p2 = * (uint16_t *) p;
复制uint16_t
整体,而不是尝试将其塞入单个字节。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.