C语言 * ((uint32_t)foo)返回什么

toiithl6  于 2023-03-22  发布在  其他
关注(0)|答案(3)|浏览(132)

看看代码:

#include <stdio.h>
#include <stdint.h>

int main() {

    char foo[512]={};

    printf("%d", *((uint32_t*)foo));

    return 0;
}

我很难理解*((uint32_t*)foo))是做什么的,在数组中使用不同的值,我得到了各种各样的返回值,它到底指向什么,那么返回值是什么?

2vuwiymt

2vuwiymt1#

  • char foo[512]={};是无效的语法,C中不允许空的初始化列表。如果你想初始化它,你必须使用{0}
  • (uint32_t*)foo是可疑的,因为uint32_t*不一定与char*兼容。此外,char数组可能没有对齐。1)经验法则是,我们可以将任何对象指针类型转换为*字符指针类型,但不能反过来
  • *((uint32_t*)foo)调用未定义的行为,可能有几种方式。foo可能未对齐。它也是一个严格的指针别名违规(What is the strict aliasing rule?)。TL;DR基本上是编译器可以自由地假设char数组从未在您发布的代码中使用,因为它可以自由地假设char永远不会通过uint32_t*访问。

忽略上述所有情况--我们不应该这样做,因为未定义的行为意味着任何事情都可能发生--那么很可能(但不保证)编译器将从char数组中抓取4个字节并将其重新解释为uint32_t。也就是说,如果我们执行char foo[512]={'A','B','C','D'};并且CPU具有小字节序格式,那么'D'将结束在uint32_t.What is CPU endianness?的最低字节中。它将变成数字0x44434241
请注意,%d是打印uint32_t的错误格式说明符。您应该使用%uinttypes.h中最正确的格式printf("%"PRIu32, ...)
1)C176.3.2.3是C标准中的相关规则:
指向一个对象类型的指针可以转换为指向另一个对象类型的指针。如果结果指针没有正确对齐引用的类型,则行为未定义。否则,当再次转换回来时,结果将与原始指针进行比较。

e5nszbig

e5nszbig2#

*((uint32_t*)foo))

在这个表达式中,foo被类型转换为uint32_t指针,然后被解引用。
将变量从一种类型的指针转换为另一种类型通常违反严格的别名规则¹,并且

*((uint32_t*)foo))

所以表达式调用了未定义的行为。
此外,foo可能未正确对齐:
C11:
1在以下情况下,行为未定义:
....
两种指针类型之间的转换会产生不正确对齐的结果(6.3.2.3)
6.3.2.3p7表示
[...]如果结果指针没有正确对齐[68]引用的类型,则行为未定义。[...]
未对齐的数据是地址(指针值)上的数据,它不能被其对齐方式(通常是其大小)整除。
注意,空的初始化列表在C23之前是无效的,仅仅因为int32_t在你的编译器/平台上碰巧是int并不意味着它在另一个编译器/平台上可能不是long
%d不是int32_t的正确格式说明符。如果您不想使用固定宽度整数类型的特定宏,另一种方法是转换为intmax_t/uintmax_t并分别使用%jd%ju

脚注:

1
参见:What is the strict aliasing rule?

oyjwcjzk

oyjwcjzk3#

它被称为***“指针双关”***。它用于将一种类型的二进制表示重新解释为另一种类型。它调用“未定义行为”UB,必须避免
一个更好(也更安全)的方法是使用memcpy函数。现代优化编译器在很多情况下都会优化memcpy的调用。
示例:

uint32_t charAsuint32(const char *charr)
{
    uint32_t result;

    memcpy(&result, charr, sizeof(result));
    return result;
}

生成的代码:

charAsuint32:
        mov     eax, DWORD PTR [rdi]
        ret

PS你使用了错误的格式来显示uint32_t值-而且它也是一个UB。
您的示例:

int main(void) 
{
    char foo[512]={0x11,0x22,0x33,0x44};
    uint32_t u32;

    memcpy(&u32, foo, sizeof(u32));

    printf("%"PRIx32"\n", u32);

    return 0;
}

https://godbolt.org/z/E1eTc8djj

相关问题