【问题标题】:Confusion about pointer casts in c关于 c 中的指针强制转换的困惑
【发布时间】:2021-06-23 18:37:43
【问题描述】:
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”。我的逻辑有问题吗?

【问题讨论】:

  • 好吧,除了严格地说您不能将 char 指针强制转换为任何奇数类型之外,这通常可以按预期工作。观察:(1)p[0] + 1'f' + 1,其中'g'; (2)*p2 = *(uint16_t*) p给一个char(即*p2,也就是p2[0])赋值一个16位的int值,超出了一个char的取值范围。 (3) p2[1],与你所想的相反,从未被分配。
  • 还要考虑您正在使用的系统的字节序。当您将该 char 指针强制转换为 unit16 指针时,可以以不同的顺序读取字节。

标签: c pointers casting


【解决方案1】:

据我了解,如果我将 p 类型转换为 uint16_t* 并取消引用它,则返回值应该是 p 指向的前 2 个字节。

这是不正确的,至少有两个原因。

一个,指向char 的指针可能没有uint16_t 所需的对齐方式,然后根据C 2018 6.3.2.3 7,C 标准没有定义到uint16_t 的转换:

...如果结果指针未正确对齐 70) 对于引用的类型,则行为未定义...

这不适用于问题中的示例代码,因为char * 是从malloc 分配的,而malloc 总是返回一个适合任何基本类型的地址。但是,它可能适用于以其他方式创建的char *(包括向p 添加偏移量,例如尝试将p+1 转换为uint16_t *)。

二,访问定义为char的对象(包括那些通过将char值写入分配给malloc的内存而创建的对象)就像uint16_t一样违反了C 2018 6.5 7中的别名规则。 C 实现可能会将两个 char 重新解释为 uint16_t,但编译器的优化也可能会将未定义的行为转换为其他行为。

*p2 = *(uint16_t*) p;

此代码是对单个字符*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,而不是将其塞进一个字节中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 2012-11-04
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多