为什么这种检测机器存储方法的方式不正确?(使用 C 语言)



我在做作业时错过了一个问题。

计算机存储器在存储数据的地方有大端存储和小端存储两种方法,为了检测一种机器存储方法,一位学生编写了以下程序:

union NUM {
    int a;
    char b;
} num;
int main(){
    num.b = 0xff;
    if (num.a! = 0xff)
        printf ("bigend");
    else 
        printf ("smallend");
    return 0;
}

但他发现运行在x86机器上的程序,打印出来的其实是'bigend',这显然是错误的。你知道问题出在哪里吗?应该如何修改此程序?

我问过我的老师,这个话题是正确的。我在某些网站上找到了一些信息,但这让我更加困惑。为什么这个问题没有错?问题到底出在哪里?

假设一个int(以及整个联合)是 4 个字节,写入 num.b 只写入这 4 个字节中的一个,其余部分未初始化。 随后读取num.a读取这些未初始化的字节,调用未定义的行为。

联合中的字节必须设置为全部 0,以便明确定义内容。

#include <stdio.h>
#include <string.h>
union NUM {
    int a;
    char b;
} num;
int main(){
    // set all bytes of num to 0 first
    memset(&num, 0, sizeof(num));
    num.b = 0xff;
    if (num.a! = 0xff)
        printf ("bigend");
    else 
        printf ("smallend");
    return 0;
}

类型双关语是 C 语言中未定义的行为。当您读取num.a时,您违反了严格的别名规则,因此允许编译器生成可能返回任何内容的代码。它确实如此。

为避免这种情况,您需要使用 memcpy()

int a = 0x00010203;
char bytes[sizeof(a)];
memcpy(bytes, &a, sizeof(a));
if(bytes[0] == 03) {
    printf("small endiann");
} else ...

最新更新