11

我使用的是 Ubuntu 16.04.5 和 GCC 版本 5.4.0。

我在玩sizeof()运营商,写了下面的代码:

#include <stdio.h>

int main(int argc, char *argv[]){

        long int mylint = 31331313131.1313;

        printf("size of long int is %d\n", sizeof(mylint));
        printf("size of long int is %d\n", sizeof(long int));

        return 0;
}

我尝试使用gcc -o ... ...命令进行编译并期待:

size of long int is 8
size of long int is 8

但我收到以下错误:

fl_double_lint.c: In function ‘main’:
fl_double_lint.c:11:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]

  printf("size of long int is %d\n", sizeof(mylint));
         ^
fl_double_lint.c:12:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
  printf("size of long int is %d\n", sizeof(long int));

当我%ld改用它时,它按预期工作。为什么sizeof()不合作%d?(为什么是' long unsigned int'而不是' int'?)

编辑:我知道有很多关于 sizeof() 运算符输出的问题(如评论中所建议的那样)。但是,他们没有回答为什么 using%d不起作用(即没有给出任何结果)的问题。我知道这不是正确的格式,但是每当我们使用char类型变量时,我们都%d可以得到等效int的结果,简而言之,uint8_t、uint16_t、uint32_t 也是如此(通常用于等于或小于 32 位的类型)。以下代码有效:

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

int main(int argc, char *argv[]){

        char mychar = 'd';
        uint32_t myuint32 = 32;
        uint16_t myuint16 = 16;
        uint8_t myuint8 = 8;
        short myshort = 26945;
        int myint = 100;

        printf("integer equivalent of mychar is %d\n", mychar);
        printf("integer equivalent of myuint8 is %d\n", myuint8);
        printf("integer equivalent of myuint16 is %d\n", myuint16);
        printf("integer equivalent of myuint32 is %d\n", myuint32);
        printf("character equivalent of myint is %c\n", myint);
        printf("integer equivalent of myshort is %d\n", myshort);


        return 0;
}

结果是:

integer equivalent of mychar is 100
integer equivalent of myuint8 is 8
integer equivalent of myuint16 is 16
integer equivalent of myuint32 is 32
character equivalent of myint is d
integer equivalent of myshort is 26945

现在我发现这%d不适用于需要存储大于 32 位的任何变量。在考虑了这个问题之后,我对 的实现依赖性有了一些想法size_t,也许在我的系统中它是unsigned long%ld也给出了结果证明了这一点)。所以也许如果size_tunsigned int我的系统中我会得到一个结果,是真的吗?

从上面的代码可以看出,%c将最后 8 位解码int为一个字符,为什么%d不这样做(即按原样解码size_t变量内容的最后 32 位int?我相信如果它会这样做我们可以对于足够小的数字得到相同的结果,这就是我最初问这个问题时的意思)。

4

1 回答 1

26

sizeof运算符计算为 type 的值size_t。此类型是无符号的,通常大于int,这就是您收到警告的原因。

使用错误的格式说明符printf调用未定义的行为。但是,对于小于C 标准第 6.3.1.1p2 节中整数提升int规则的类型,您可以避免这种情况:

可以在可以使用 int 或 unsigned int 的表达式中使用以下内容:

  • 具有整数类型(除 int 或 unsigned int 之外)的对象或表达式,其整数转换等级小于或等于 int 和 unsigned int 的等级。
  • _Bool、int、signed int 或 unsigned int 类型的位域。

如果 int 可以表示原始类型的所有值(受宽度限制,对于位域),则该值将转换为 int ;否则,它将转换为 unsigned int 。这些被称为整数促销。整数提升不会改变所有其他类型。

因此,只要这不会导致从无符号变为有符号,小于int可以打印的类型%d

正确的类型修饰符size_t是,根据C 标准%zu的第 7.21.6.1p7 节关于函数的长度修饰符(以及扩展,):fprintfprintf

z

指定后面的 d 、 i 、 o 、 u 、 x 或 X 转换说明符适用于 asize_t或相应的有符号整数类型参数;或者后面的 n 转换说明符适用于指向对应于size_t 参数的有符号整数类型的指针。

所以你想要的是:

printf("size of long int is %zu\n", sizeof(mylint));
于 2019-01-31T15:17:33.887 回答