以下 C 代码的输出

Output of the following C code

以下 C 代码的输出是什么。假设它在 Little endian 机器上运行,其中 short int 占用 2 个字节,char 占用 1 个字节。

#include<stdio.h>
int main() {
    short int c[5];
    int i = 0;
    for(i = 0; i < 5; i++)
        c[i] = 400 + i;
    char *b = (char *)c;
    printf("%d", *(b+8));
    return 0;
}

在我的机器上它给出了

-108

我不知道我的机器是小端还是大端。我在某个地方发现它应该给

148

作为输出。因为404的低8位(即元素c[4])是148。但我认为由于“%d”,它应该从c[4]的地址开始从内存中读取2个字节。

要查看您的系统中类型的大小:

printf("char = %u\n", sizeof(char));    
printf("short = %u\n", sizeof(short));    
printf("int = %u\n", sizeof(int));    
printf("long = %u\n", sizeof(long));    
printf("long long = %u\n", sizeof(long long));  

更改程序中的行

unsigned char *b = (unsigned char *)c;
printf("%d\n", *(b + 8));

和简单测试(我知道这不能保证,但我知道的所有 C 编译器都是这样做的,我不关心具有不同地址和指向不同类型数据的指针的旧 CDC 或 UNISYS 机器

printf(" endianes test: %s\n", (*b + (unsigned)*(b + 1) * 0x100) ==  400? "little" : "big");

再说一句:只是因为在你的程序中c[0] == 400

c[4] 存储 404。在双字节小端表示法中,这意味着两个字节 0x94 0x01,或(十进制)148 1.

b+8 寻址 c[4] 的内存。 b 是指向 char 的指针,因此 8 表示添加 8 个字节(即 4 个两字节短)。也就是说,b+8指向c[4]的第一个字节,其中包含148.

*(b+8)(也可以写成 b[8])取消对指针的引用,从而将值 148 作为 char。这是实现定义的:在许多常见平台上 char 是一个有符号类型(范围为 -128 .. 127),所以它实际上不能是 148.但是如果是无符号类型(范围是0..255),那么148就可以了。

148 的二进制位模式是 10010100。将其解释为二进制补码可以得到 -108.

这个 char 值(148-108 的)然后自动转换为 int 因为它出现在可变参数函数的参数列表中(printf)。这不会更改值。

最后,"%d" 告诉 printf 获取 int 参数并将其格式化为十进制数。

所以,回顾一下:假设您有一台机器

  • 一个字节是8位
  • 负数使用补码
  • short int 是 2 个字节

... 那么该程序将输出 -108(如果 char 是有符号类型)或 148(如果 char 是无符号类型)。

代码在不同的计算机上给出不同的输出,因为在某些平台上 char 类型默认已签名,而在其他平台上默认未签名。这与字节顺序无关。试试这个:

    char *b = (char *)c;
    printf("%d\n", (unsigned char)*(b+8)); // always prints 148 
    printf("%d\n", (signed char)*(b+8));   // always prints -108 (=-256 +148)

默认值取决于平台和编译器设置。您可以使用 GCC 选项 -fsigned-char-funsigned-char.

控制默认行为