sizeof运算符在按位和失败时失败在C.

时间:2014-09-07 05:37:38

标签: c sizeof bitwise-and

感谢您的回复,%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运算符的说明符的使用影响 提前谢谢。

2 个答案:

答案 0 :(得分:6)

理论

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

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

您正在使用需要%d的{​​{1}}来打印int,这是(a)无符号类型和(b)最可能是8个字节,而不是像size_t这样的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)。但是,如果您支持int,则该库不太可能不支持long long

如果您使用GCC,它应该一直警告您参数列表中的类型不匹配%zu

当您使用错误的类型时,会从printf()内的堆栈中拾取错误的值。你在堆栈上推送4个8字节的单元,但告诉printf()读取4个字节,8个字节,4个字节和8个字节。


编译和修复代码

使用原始代码printf()进行微小修改:

sz1.c

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

#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 -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

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

#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;
}

但是,编译相同的代码为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 = 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
$

为什么?

  

如果我使用$ ./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?

由于数据堆叠的方式。假设你有一个32位的编译,那就是&#39; ODD&#39;致电%lld推动:

  1. 指向格式的指针。
  2. 8个字节表示printf()的值(因为x&yx都是y,因此long long也是x&y
  3. 4个字节表示long long的值(假设编译为32位,sizeof(x&y)
  4. 格式错误告诉sizeof(size_t) == 4

    1. 它应该使用堆栈中的4个字节来打印第一个值(printf()) - %d - 而不是正确的8个字节。
    2. 它应该使用堆栈中的8个字节来打印第二个值(x&y) - %lld - 而不是正确的4个字节。
    3. 因为机器是little-endian(可能是Intel机器),无论值是4个字节还是8个字节,前4个字节都是相同的,但是其余部分的错误解释是因为从末尾开始的4个字节的零sizeof(x&y)值的值被视为值的一部分。将格式从x&y更改为%lld(在原始代码中),从0x%llX更改为%zu,并且ODD行更改:

      0x%zX

      0x8之后有8个零。

答案 1 :(得分:2)

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

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