如果我在c中使用%d而不是%ld会怎么样?

如果我在c中使用%d而不是%ld会怎么样?,c,integer,printf,C,Integer,Printf,我是一个初学者,看了《C初级读物+》一书,对这句话感到困惑 要打印长值,请使用%ld格式说明符。如果系统上的int和long大小相同,只需%d即可,但当您的程序传输到两种类型不同的系统时,将无法正常工作,因此请长时间使用%ld说明符 我自己测试了它,代码如下: int num = 2147483647; short num_short = 32767; long num_long = 2147483647; printf("int: %d; short: %d; long: %d&qu

我是一个初学者,看了《C初级读物+》一书,对这句话感到困惑

要打印长值,请使用
%ld
格式说明符。如果系统上的int和long大小相同,只需
%d
即可,但当您的程序传输到两种类型不同的系统时,将无法正常工作,因此请长时间使用
%ld
说明符

我自己测试了它,代码如下:

int num = 2147483647;
short num_short = 32767;
long num_long = 2147483647;
printf("int: %d; short: %d; long: %d", num, num_short, num_long);
该计划运作良好

我在网上搜索发现了这个问题: 答复说:

它之所以有效,是因为long int和int实际上是相同的数字表示形式:四个字节,两个字节的补码。对于另一个平台(例如x86-64 Linux),情况可能并非如此,您可能会看到某种问题


我的电脑是64位的。整数是32位。长整数是32位。短整数是16位(我检查过了,没问题)。所以你可以看到int类型和short int类型是不同的。这个答案还说,如果这些类型具有不同的数字表示形式,则会导致错误。那么作者所说的是什么意思呢?

你的书的作者所说的是正确的

测试调用未定义的行为,因为标准没有指定使用错误格式说明符时会发生什么。这意味着每个编译器的实现都可以自由解释如何管理此类情况

然而,通过一些常识(以及对“实践中”事物如何工作的一点了解),你所经历的行为可以得到解释

每个格式说明符都会告诉编译器,在参数列表中,它可以找到要打印的参数。因此,这也是您的书的断言的核心,传递一个具有意外长度的整数会使以下格式说明符在错误的位置检索参数


示例1:32位整数的序列 让我们从一个“正常”序列开始,以获得一个基本示例

int a=1, b=2;
printf("%d %d\n", a, b);
指定的格式告诉编译器将在格式字符串之后找到两个4字节整数。参数实际上是以预期的方式放置在堆栈中的

-------------------------------------------------
  ... format string | a (4 bytes) | b (4 bytes) |
-------------------------------------------------

示例2:为什么用
%d
打印64字节
长的
不起作用?

让我们考虑下面的<代码> Prtff <代码>:

long int a=1;
int b=2;
printf("%d %d\n", a, b);
short int a=1;
int b=2;
printf("%d %d\n", a, b);
指定的格式告诉编译器将在格式字符串之后找到两个4字节整数。但是第一个参数需要8字节而不是4字节

-------------------------------------------------------------
  ... format string | a (4 bytes) + (4 bytes) | b (4 bytes) |
-------------------------------------------------------------
                      ^             ^
                      Compiler      Compiler
                      expects 'a'   expects 'b'
                      here          here
因此,输出将是

1 0
1 1
因为
b
是在
a
的4个最高有效字节所在的位置搜索的,它们都是0


示例3:为什么用
%d
打印16字节的

让我们考虑下面的<代码> Prtff <代码>:

long int a=1;
int b=2;
printf("%d %d\n", a, b);
short int a=1;
int b=2;
printf("%d %d\n", a, b);
指定的格式告诉编译器将在格式字符串之后找到两个4字节整数。第一个参数只需要两个字节而不是4个字节,但是我们很幸运,因为在32位平台上,参数是4字节对齐的

---------------------------------------------------------------------
  ... format string | a (2 bytes) | (2 bytes PADDING) | b (4 bytes) |
---------------------------------------------------------------------
                      ^                               ^
                      Compiler                        Compiler
                      expects 'a'                     expects 'b'
                      here                            here
因此,输出将是

1 0
1 1
因为在正确的位置搜索了
b
。如果对齐是使用非0填充完成的,那么在
a
的表示中会出现问题,但事实并非如此


因此,在
%d
用于
short
的情况下,真正的区别只是符号字节的表示,因为符号位应该是最重要的。

您的书的作者所说的是正确的

测试调用未定义的行为,因为标准没有指定使用错误格式说明符时会发生什么。这意味着每个编译器的实现都可以自由解释如何管理此类情况

然而,通过一些常识(以及对“实践中”事物如何工作的一点了解),你所经历的行为可以得到解释

每个格式说明符都会告诉编译器,在参数列表中,它可以找到要打印的参数。因此,这也是您的书的断言的核心,传递一个具有意外长度的整数会使以下格式说明符在错误的位置检索参数


示例1:32位整数的序列 让我们从一个“正常”序列开始,以获得一个基本示例

int a=1, b=2;
printf("%d %d\n", a, b);
指定的格式告诉编译器将在格式字符串之后找到两个4字节整数。参数实际上是以预期的方式放置在堆栈中的

-------------------------------------------------
  ... format string | a (4 bytes) | b (4 bytes) |
-------------------------------------------------

示例2:为什么用
%d
打印64字节
长的
不起作用?

让我们考虑下面的<代码> Prtff <代码>:

long int a=1;
int b=2;
printf("%d %d\n", a, b);
short int a=1;
int b=2;
printf("%d %d\n", a, b);
指定的格式告诉编译器将在格式字符串之后找到两个4字节整数。但是第一个参数需要8字节而不是4字节

-------------------------------------------------------------
  ... format string | a (4 bytes) + (4 bytes) | b (4 bytes) |
-------------------------------------------------------------
                      ^             ^
                      Compiler      Compiler
                      expects 'a'   expects 'b'
                      here          here
因此,输出将是

1 0
1 1
因为
b
是在
a
的4个最高有效字节所在的位置搜索的,它们都是0


示例3:为什么用
%d
打印16字节的

让我们考虑下面的<代码> Prtff <代码>:

long int a=1;
int b=2;
printf("%d %d\n", a, b);
short int a=1;
int b=2;
printf("%d %d\n", a, b);
指定的格式告诉编译器将在格式字符串之后找到两个4字节整数。第一个参数只需要两个字节而不是4个字节,但是我们很幸运,因为在32位平台上,参数是4字节对齐的

---------------------------------------------------------------------
  ... format string | a (2 bytes) | (2 bytes PADDING) | b (4 bytes) |
---------------------------------------------------------------------
                      ^                               ^
                      Compiler                        Compiler
                      expects 'a'                     expects 'b'
                      here                            here
因此,输出将是

1 0
1 1
因为在正确的位置搜索了
b
。如果对齐是使用非0填充完成的,那么在
a
的表示中会出现问题,但事实并非如此


因此,在
%d
用于
short
的情况下,真正的区别仅仅是有符号字节的表示,因为符号位应该是最重要的。

发生什么取决于实现。这个