当前位置: 首页 > 知识库问答 >
问题:

使用%ld转换说明符在C中打印双精度类型

林博厚
2023-03-14

这是部分源代码(来自《C primer plus》一书的示例代码):

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个字节(float转换为double)。类似地,它为n2多放置8个字节,然后分别为n3和n4放置4个字节。然后控制权转移到printf()函数。此函数从堆栈中读取值,但在执行此操作时,它会根据转换说明符读取这些值。%ld说明符指示printf()应该读取4个字节,因此printf)读取堆栈中的前4个字节作为其第一个值。这只是n1的前半部分,它被解释为一个长整数。下一个%ld说明符再读取4个字节;这只是n1的后半部分,被解释为第二个长整数(见图4.9)。类似地,%ld的第三个和第四个实例会导致读取n2的第一个和第二个半部分,并将其解释为另外两个长整数,因此,尽管我们有正确的n3和n4说明符,printf()读取的字节是错误的。

我能得到书上说的,我自己的PC对每种数据类型使用的内存和上面一样。< br >但是,当我自己编译并运行代码时,我得到了以下输出:< br > < code > 20000000000 1234567890 2147483626 0 < br >我的开发环境是:Ubuntu16.04LTS,gcc 5.4.0,C11 standard。< br >我不知道是什么原因导致了我自己的输出与预期的输出之间的差异。

共有2个答案

柯正谊
2023-03-14

来自标准§7.21.6.6¶9

如果转换规范无效,则行为未定义.282) 如果任何参数不是相应转换规范的正确类型,则行为未定义。

这就是你的问题所在。你可以阅读标准,你会发现标准从来没有说过你必须使用堆栈或堆来实现内存访问或类似的东西。要给出未定义行为的原因,请在每个案例上读取并打印sizeof(long)(来自%ldformat说明符)。但存储双精度或其他变量所需的内存量可能与此不同。在大多数情况下,这将打印原始变量的某些部分。这是未定义的行为,这是正确的说法。

使用正确的格式说明符(%f 表示浮点型和双精度型)。

越昊穹
2023-03-14

这是一种常见的方法。程序将这些值放在一个叫做堆栈的内存区域中。当计算机将这些值放入堆栈时,它是由变量的类型决定的,而不是由转换说明符决定的

这在大多数32位系统上是正确的,但在64位系统上,调用约定是不同的,如果可能的话,参数在寄存器中传递。

看这个(系统V AMD64 ABI是这里相关的)。

确保的一种方法是查看程序的程序集输出。使用 gcc,您可以使用 -S 输出程序集而不是二进制文件。

(请注意,我在这里只谈论linux。事情可能会因您的操作系统而异,因为这是一种未定义的行为,您的编译器甚至您的编译器版本或标志)

 类似资料:
  • 有人能解释一下printf中的是如何使用说明符“%g”的吗?下面的输出让我很困惑: 我了解到使用最短的表示形式。 但是下面的输出仍然让我困惑 我的问题是:为什么能给出确切的数字,而不能? 似乎16个有效数字是准确的。有人能告诉我原因吗?

  • 我需要将字符串值转换为带点的双精度值。下面是简单的代码 当我给出10000或100000这样的值时,它是有效的。帮助我克服这个问题。

  • 问题内容: 我有一个双,其值是10,000,000.00(千万)。我必须将其转换为。当使用该方法时,我会得到 “ 1.0E7”,它遵循规范是正确的。不幸的是,我需要“ 10,000,000.00”(或等价的语言,具体取决于语言环境)。 如何做到这一点? 问题答案: 尝试之一 NumberFormat http://java.sun.com/javase/6/docs/api/java/text/N

  • 问题内容: 我想在Java中打印双精度值而不使用指数形式。 它显示此E表示法:。 我希望它像这样打印它: 防止这种情况的最佳方法是什么? 问题答案: 你可以使用同: 这将打印。如果你不想要小数部分,请使用 这使用了文档中说明的格式说明符语言。

  • 我还是一名学生,刚开始学习java编程语言,我只是想问一下如何将函数main中的参数从字符串转换为double,就像将字符串转换为整数一样。pasreInt(arg)

  • 我想用一个小数点和一个小数位的格式将任何双精度四舍五入为双精度,这样29575.347434将是2.3。 我试着用decimalFormat做这个,但当我试着我只得到了一个29575.3格式的字符串,带有一个,我不知道如何在保留值为双精度的同时去掉所有小数点。