简体   繁体   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]);

So I created a char* p to store the string "fungus".所以我创建了一个 char* p 来存储字符串“fungus”。 To my understanding, if I typecast p to a uint16_t* and dereference it, the returned value should be the first 2 bytes pointed to by p.据我了解,如果我将 p 类型转换为 uint16_t* 并取消引用它,则返回的值应该是 p 指向的前 2 个字节。 So, p2[1] should be "u", since "u" is the second byte in the string "fungus".因此,p2[1] 应该是“u”,因为“u”是字符串“fungus”中的第二个字节。 However, this isn't the case when I run my program.但是,当我运行我的程序时,情况并非如此。 I've also tried to print p[0] + 1, but this just outputs "g".我也尝试打印 p[0] + 1,但这只是输出“g”。 Is there an error in my logic?我的逻辑有错误吗?

To my understanding, if I typecast p to a uint16_t* and dereference it, the returned value should be the first 2 bytes pointed to by p.据我了解,如果我将 p 类型转换为 uint16_t* 并取消引用它,则返回的值应该是 p 指向的前 2 个字节。

This is not correct, for at least two reasons.这是不正确的,至少有两个原因。

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: 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:

… If the resulting pointer is not correctly aligned70) for the referenced type, the behavior is undefined… ... 如果结果指针未正确对齐 70) 用于引用类型,则行为未定义...

That will not apply in the example code in the question, since the char * is assigned from malloc , and malloc always returns an address suitably aligned for any fundamental type.这不适用于问题中的示例代码,因为char *是从malloc分配的,并且malloc始终返回适合任何基本类型对齐的地址。 However, it may apply to char * created in other ways (including by adding offsets to p , such as attempting to convert p+1 to uint16_t * ).但是,它可能适用于以其他方式创建的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 , but it is also possible that optimization by the compiler might transform the undefined behavior into something else. 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;

This code is an assignment to the single char *p2 , which is p2[0] , regardless of the fact that the right-hand side may be a 16-bit value.此代码是对单个 char *p2的赋值,即p2[0] ,而不管右侧可能是 16 位值。 It does not touch p2[1] .它不触及p2[1]

If *(uint16_t*) p;如果*(uint16_t*) p; does reinterpret two eight-bit bytes of the string as a uint16_t , then it will produce some 16-bit value that is then assigned to the single char *p2 .确实将字符串的两个 8 位字节重新解释为uint16_t ,然后它将产生一些 16 位值,然后分配给单个char *p2 If char is unsigned, this will store the low eight bits of that value as p2[0] , leaving p2[1] untouched.如果char是无符号的,则该值的低八位将存储为p2[0] ,而p2[1]保持不变。 If it is signed, an implementation-defined conversion will be performed, and the result (if a trap does not occur) will be assigned to p2[0] , again leaving p2[1] untouched.如果已签名,则将执行实现定义的转换,并将结果(如果未发生陷阱)分配给p2[0] ,同样保持p2[1]不变。

Then printf("\nPointer: %c\n", p2[1]);然后printf("\nPointer: %c\n", p2[1]); attempts to print a value that has not been initialized, since nothing has put a value in p2[1] .尝试打印尚未初始化的值,因为p2[1]中没有任何值。

You could try changing *p2 = *(uint16_t*) p;您可以尝试更改*p2 = *(uint16_t*) p; to * (uint16_t *) p2 = * (uint16_t *) p;* (uint16_t *) p2 = * (uint16_t *) p; to copy the uint16_t whole, instead of trying to cram it into a single byte.复制uint16_t整体,而不是尝试将其塞入单个字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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