繁体   English   中英

关于 c 中的指针转换的混淆

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM