-2

感谢您的回复,%zu 说明符可以与 sizeof 运算符一起使用,大小可以正常打印,x 和 y 值也可以。但是当我将所有这些说明符更改为 %lld 时,它应该打印实际的 x 和 y 值(因为它们很长),它会打印一些随机垃圾值。

    #include<stdio.h>

    int main()
    {
      long long x=500000000007;
      long long y=1;
      printf("size of x : %lld,x = %lld, size of y : %lld, y : %lld\n",sizeof(x),x,sizeof(y),y); 

      if(x & y)
      {
        printf("ODD IT IS :), x&1 = %lld, size of x&1 = %lld\n",x&y,sizeof(x&y) );//<--- this line
      }



      printf("After If statement ---> size of x : %lld,x = %lld\n",sizeof(x),x); 

      return 0;
    }

    Output on linux 32 bit system(Ubuntu) using gcc compiler
      size of x : 7661335479756783624,x = 34359738484, size of y : 1, y : -4160453359
      ODD IT IS :), x&1 = 1, size of x&1 = 34359738376
      After If statement ---> size of x : 7661335479756783624,x = 34359738484

现在,问题是 - 为什么变量 x 和 y 中的值会受到使用 sizeof 运算符的说明符的影响提前谢谢。

4

2 回答 2

6

理论

问题是您没有使用正确的格式规范来打印sizeof().

printf("size of x : %d,x = %lld, size of y : %d, y : %lld\n", sizeof(x), x, sizeof(y), y); 

您正在使用%d,它需要一个int,来打印 a size_t,它是(a)一个无符号类型和(b)很可能是 8 个字节,而不是像 an 那样的 4 个字节int。正确的打印方式size_t(如 的结果sizeof)是使用z修饰符:

printf("size of x: %zu, x = %lld, size of y: %zu, y = %lld\n", sizeof(x), x, sizeof(y), y);

如果您在库中不支持%zu,则将sizeof(x)etc的结果int显式转换为。但是,如果您支持long long,则库不太可能不支持%zu.

如果您使用 GCC,它应该会警告您参数列表中的类型不匹配到printf().

当你使用错误的类型时,错误的值会从内部的堆栈中被挑选出来printf()。您将 4 个 8 字节单元压入堆栈,但printf()要读取 4 字节、8 字节、4 字节和 8 字节。


编译和修复代码

采用您的原始代码,sz1.c稍作修改:

#include <stdio.h>

int main(void)
{
    long long x=500000000007;
    long long y=1;

    printf("size of x : %d, x = %lld, size of y : %d, y : %lld\n", sizeof(x), x, sizeof(y), y); 
    printf("ODD IT IS :), x&1 = %d, size of x&1 = %lld\n", x&y, sizeof(x&y));
    printf("After If statement ---> size of x : %d, x = %lld\n", sizeof(x), x); 

    return 0;
}

然后编译它给了我很多警告(这是 GCC 4.8.1,出于某种原因,它会为格式警告生成每个警告的两个副本——这很糟糕,但不是那么糟糕!):

$ gcc -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition     sz1.c -o sz1
sz1.c: In function ‘main’:
sz1.c:8:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
     printf("size of x : %d, x = %lld, size of y : %d, y : %lld\n", sizeof(x), x, sizeof(y), y); 
     ^
sz1.c:8:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
sz1.c:8:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
sz1.c:8:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
sz1.c:9:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long long int’ [-Wformat=]
     printf("ODD IT IS :), x&1 = %d, size of x&1 = %lld\n", x&y, sizeof(x&y));
     ^
sz1.c:9:5: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
sz1.c:9:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long long int’ [-Wformat=]
sz1.c:9:5: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
sz1.c:10:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
     printf("After If statement ---> size of x : %d, x = %lld\n", sizeof(x), x); 
     ^
sz1.c:10:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
$

此版本 ,sz2.c具有正确的类型说明符(因此编译时没有任何警告):

#include <stdio.h>

int main(void)
{
    long long x=500000000007;
    long long y=1;
    printf("size of x : %zu, x = %lld, size of y : %zu, y : %lld\n", sizeof(x), x, sizeof(y), y); 
    printf("ODD IT IS :), x&1 = %lld, size of x&1 = %zu\n", x&y, sizeof(x&y) );//<--- this line
    printf("After If statement ---> size of x : %zu, x = %lld\n", sizeof(x), x); 
    return 0;
}

有趣的是,在 Mac OS X 10.9.4 和 GCC 4.8.1 上,两个程序的输出基本相同:

$ ./sz1 
size of x : 8, x = 500000000007, size of y : 8, y : 1
ODD IT IS :), x&1 = 1, size of x&1 = 8
After If statement ---> size of x : 8, x = 500000000007
$ ./sz2
size of x : 8, x = 500000000007, size of y : 8, y : 1
ODD IT IS :), x&1 = 1, size of x&1 = 8
After If statement ---> size of x : 8, x = 500000000007
$

但是,将相同的代码编译为 32 位而不是 64 位可执行文件,则存在差异:

$  ./sz1 
size of x : 8, x = 500000000007, size of y : 8, y : 1
ODD IT IS :), x&1 = 1, size of x&1 = 34359738368
After If statement ---> size of x : 8, x = 500000000007
$ ./sz2
size of x : 8, x = 500000000007, size of y : 8, y : 1
ODD IT IS :), x&1 = 1, size of x&1 = 8
After If statement ---> size of x : 8, x = 500000000007
$

为什么?

如果我使用打印它,为什么它的尺寸会大到 34359738368 %lld

由于数据的堆叠方式。假设您有 32 位编译,“ODD”调用printf()推送:

  1. 指向格式的指针。
  2. 8 个字节的值x&y(因为xy都是long long,所以x&y也是 a long long)。
  3. 4 个字节的值sizeof(x&y)(假设是 32 位编译,使用sizeof(size_t) == 4.

不正确的格式告诉printf()我们:

  1. 它应该使用堆栈外的 4 个字节来打印第一个值 ( %d) — x&y— 而不是正确的 8 个字节。
  2. 它应该使用堆栈外的 8 个字节来打印第二个值 ( %lld) — sizeof(x&y)— 而不是正确的 4 个字节。

因为机器是little-endian(可能是Intel机器),所以无论值是4字节还是8字节,前4个字节都是一样的,但是会出现对其余部分的误解,因为从x&y值的末尾开始的4个字节的零被视为价值的一部分。将格式从%lldto 0x%llX(在原始代码中)和 from更改%zu0x%zX,并且 ODD 行更改:

ODD IT IS :), x&1 = 1, size of x&1 = 0x800000000

ODD IT IS :), x&1 = 1, size of x&1 = 0x8

0x8 后面有 8 个零。

于 2014-09-07T05:52:33.420 回答
2

sizeof是编译时运算符(操作数是可变长度数组时除外)。给定long long x,sizeof(x)等价于sizeof(long long),它不会在运行时改变。

long long类型至少为 64 位,在您的机器中,它是 8 个字节(64 位)。所以没有什么奇怪的。

于 2014-09-07T05:44:14.293 回答