Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ printf-奇怪类型的mash结果。有人能解释一下吗?_C++_C_Struct_Printf - Fatal编程技术网

C++ printf-奇怪类型的mash结果。有人能解释一下吗?

C++ printf-奇怪类型的mash结果。有人能解释一下吗?,c++,c,struct,printf,C++,C,Struct,Printf,在处理一个从二进制文件读取结构数据类型的简单项目时,我遇到了一个奇怪的printf格式类型mishmash。基本上,我大部分时间都使用%u格式来显示无符号整数,而在我的结构中,是类型为unsigned long long的成员,使用格式字符显示此数据会导致一些奇怪的情况,并且会浪费几个小时来搜索错误类型 以下是一个例子: struct bar { unsigned long long ll; unsigned int i1; unsigned int i2; }; in

在处理一个从二进制文件读取结构数据类型的简单项目时,我遇到了一个奇怪的printf格式类型mishmash。基本上,我大部分时间都使用
%u
格式来显示无符号整数,而在我的结构中,是类型为
unsigned long long
的成员,使用格式字符显示此数据会导致一些奇怪的情况,并且会浪费几个小时来搜索错误类型

以下是一个例子:

struct bar {
    unsigned long long ll;
    unsigned int i1;
    unsigned int i2;
};

int main(void)
{
    bar fubar;
    fubar.ll = 1200;
    fubar.i1 = 2500;
    fubar.i2 = 450;

    printf("Debt: %u Euro, Wallet: %u Euro, Outgoings: %u Euro.\n", fubar.ll, fubar.i1, fubar.i2);

    return 0;
}
结果:

债务:1200欧元,钱包:0欧元,支出:2500欧元

使用Visual Studio 2013编译

当然,当我使用
%llu
格式化时,一切都像预期的那样工作


这是否仅仅是因为
printf
的工作方式和实现方式而导致的?

无符号的long-long
将使用
%llu
打印。使用不匹配的变量类型会调用未定义的行为

引用
C11
,第§7.21.6.1章

ll
(ell)

指定以下d、i、o、u、x或x转换说明符应用于 长整型或无符号长整型参数

关于UB

[…]如果有任何论点 对应转换规范的类型不正确,行为为 未定义


我无法使用编译器在计算机上复制此行为。但是,报告的行为在ideone上复制:

问题是您正在调用未定义的行为。调用
printf
的第二个参数是无符号long-long,但第一个format指令是
%u
。这是不匹配的。您应该使用
%llu
作为format指令。
printf
的格式指令必须与参数匹配。如果未定义,则函数将显示未定义的行为

不知道对未定义的行为会有什么反应

我怀疑在你的计算机上,在你的编译器上(大概在ideone.com上也是如此)发生的事情是调用堆栈中填充了

  • 指向format指令的指针(四个或八个字节)
  • 值为1200(八字节)的无符号long long
  • 值为2500(四个字节)的无符号整数,以及
  • 值为450(另四个字节)的无符号整数
当看到format指令中的第一个
%u
时,
printf
检查调用堆栈中format指令后的四个字节(不是八个字节)。你大概是在一台小小的endian计算机上运行。解释为无符号int的前四个字节包含1200,所以这就是打印的内容

看到下一个
%u
printf
检查调用堆栈中的下四个字节。这四个字节是您的调用推送到调用堆栈上的无符号长字符串的高阶一半。因为1200比232小得多,所以无符号long long的上半部分都是零位。因此,
printf
在您的钱包中打印0欧元

看到最后一个
%u
printf
再次检查调用堆栈,这次从format指令结束后的8个字节开始。接下来的四个字节,作为无符号整数,包含2500。这就是
printf
输出的内容


如上所述,我在我的计算机上没有看到这种行为。我看到一种不同形式的未定义行为。不要试图理解未定义的行为。除非你真的知道自己在做什么,并且愿意承担后果(例如,不可移植性、鼻恶魔、硬盘擦除),否则不要调用未定义的行为。

。您使用的编译器是什么?未定义的行为是未定义的。相关: