下面是源代码的一部分( "C入门+“一书中的示例代码):
float n1 = 3.0;
double n2 = 3.0;
long n3 = 2000000000;
long n4 = 1234567890;
printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);预期产出如下:
0 1074266112 0 1074266112这本书明确地解释了原因:
参数传递的机制取决于实现。这就是在一个系统上传递参数的方式。函数调用如下所示:
printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);此调用告诉计算机将变量n1、n2、n3和n4的值交给计算机。这是一种常见的方法。程序将这些值放置在称为堆栈的内存区域。当计算机将这些值放在堆栈上时,它由变量的类型而不是转换说明符来指导。因此,对于n1,它将8个字节放置在堆栈上(浮点数转换为双字节)。类似地,它为n2放置了8个字节,n3和n4分别放置了4个字节。然后,控制转移到printf()函数。这个函数从堆栈中读取值,但是当它这样做时,它会根据转换说明符读取它们。%ld说明符指示printf()应该读取4个字节,因此printf()读取堆栈中的前4个字节作为其第一个值。这仅仅是n1的前半部分,它被解释为一个长整数。下一个%ld说明符多读取4个字节;这只是n1的下半部分,并被解释为第二个长整数(参见图4.9 )。类似地,%ld的第三个和第四个实例导致读取n2的第一部分和第二部分,并将其解释为两个更长的整数,因此尽管我们为n3和n4提供了正确的说明符,printf()读取的字节却是错误的。
我可以得到书上说的东西,我自己的PC机用于每一种数据类型的内存与上面的相同。
但是,当我自己编译和运行代码时,我得到了以下输出:
2000000000 1234567890 2147483626 0
我的开发环境是:Ubuntu16.04LTS,gcc 5.4.0,C11标准。
我不知道是什么导致了我自己的产出和预期的产出之间的差异。
发布于 2018-02-09 02:39:57
这是一种常见的方法。程序将这些值放置在称为堆栈的内存区域。当计算机将这些值放在堆栈上时,它是由变量的类型而不是由转换说明符引导的。
这在大多数32位系统上是正确的,但在64位系统上,调用约定是不同的,如果可能的话,参数将在寄存器中传递。
请参见这 (系统V AMD64 ABI与此处相关)。
确保的一种方法是查看程序的程序集输出。使用gcc,您可以使用-S输出程序集而不是二进制程序集。
(请注意,我只在这里讨论linux。情况可能因操作系统而异,由于这是一种未定义的行为,所以编译器,甚至编译器版本或标志)
发布于 2018-02-09 02:46:38
“标准”第7.21.6.6节
如果转换规范无效,则行为未定义.282)如果任何参数都不是对应转换规范的正确类型,则行为未定义。
这就是你的问题所在。您可以阅读该标准,您将看到标准从不说您必须使用堆栈或堆来实现内存访问或类似的东西。为了解释这种未定义的行为,sizeof (long) (来自%ld格式说明符)将在每个情况下读取并打印。但是存储双变量或其他变量所需的内存量可能与此不同。在大多数情况下,这将打印原始变量的某些部分。这是未定义的行为,这是正确的说法。
使用正确的格式说明符(%f表示浮动和双)。
https://stackoverflow.com/questions/48697853
复制相似问题