-1

我想知道为什么sizeof不能使用不同类型的格式说明符。

我知道这sizeof通常与%zu格式说明符一起使用,但我想知道我自己的知识背后发生了什么以及为什么nan在我使用它时打印它%f或在使用它时打印一个长数字%lf

int a = 0;
long long d = 1000000000000;
int s = a + d;
printf("%d\n", sizeof(a + d));  // prints normal size of expression
printf("%lf\n", sizeof(s));     // prints big number
printf("%f", sizeof(d));        // prints nan
4

2 回答 2

4

sizeof计算为 type 的值size_t。C99 中的正确说明符size_t%zu. 您可以%u在类型相同或至少具有相同大小和表示的size_t系统上使用。unsigned int在 64 位系统上,size_t值具有 64 位,因此大于 32 位整数。在 64 位 linux 和 OS/X 上,这种类型被定义为unsigned longand 在 64 位 Windows 上为unsigned long long,因此在这些系统上使用%luor%llu也很好。

为不兼容的转换规范传递 asize_t具有未定义的行为:

  • 程序可能会崩溃(如果你使用它可能会崩溃%s
  • 该程序可以显示预期值(因为它可能%d
  • 该程序可能会产生奇怪的输出,例如nanfor%f或其他东西......

原因是整数和浮点值以不同的方式传递给它们,printf并且它们具有不同的表示形式。printf在期望 a的地方传递一个整数double将让我们printf从具有随机内容的寄存器或内存位置检索浮点值。在您的情况下,浮点寄存器恰好包含一个nan值,但它可能在程序中的其他地方或稍后包含不同的值,没有任何预期,行为未定义。

一些遗留系统不支持%zu,尤其是 Microsoft 的 C 运行时。在这些系统上,您可以使用%uor%lu和使用强制转换将 the 转换size_t为 anunsigned或 an unsigned long

int a = 0;
long long d = 1000000000000;
int s = a + d;
printf("%u\n", (unsigned)sizeof(a + d));       // should print 8
printf("%lu\n", (unsigned long)sizeof(s));     // should print 4
printf("%llu\n", (unsigned long long)sizeof(d)); // prints 4 or 8 depending on the system
于 2019-10-23T19:05:05.603 回答
1

我想知道我自己的知识背后发生了什么以及为什么nan当我使用它时它会打印出来,%f或者当与它一起使用时它会打印一个长数字%lf

几个原因。

首先,printf不知道您实际传递给它的附加参数的类型。它依靠格式字符串来告诉它期望的附加参数的数量和类型。如果您将 asize_t作为附加参数传递,但告诉printf期望 a float,那么printf会将附加参数的位模式解释为 a float,而不是 a size_t。整数和浮点类型具有完全不同的表示形式,因此您会得到意想不到的值(包括 NaN)。

其次,不同的类型有不同的大小。如果您将 16 位short作为参数传递,但告诉printf期望使用 64 位double%f那么printf将立即查看该参数之后的额外字节。不能保证size_t并且double具有相同的大小,因此printf可能会忽略实际值的一部分,或者使用不属于该值的内存中的字节。

最后,这取决于参数是如何传递的。一些架构使用寄存器来传递参数(至少对于前几个参数)而不是堆栈,并且不同的寄存器用于浮点数和整数,所以如果你传递一个整数并告诉它期待一个带有 的双精度%fprintf可能会查看完全错误的地方并打印完全随机的东西。

printf不聪明。它依赖于您为要传递的参数类型使用正确的转换说明符。

于 2019-10-23T20:08:58.510 回答