在printf参数中提升类型是危险的吗?

D.C*_*.C. 7 c logging printf

我的问题源于在尝试构建多个位深度平台(例如32/64)时尝试使用printf来记录事物.

一直在养成丑陋头脑的问题是试图在多种体系结构上打印.在32位上它会是这样的

printf(" my int: %d\n", myInt);
Run Code Online (Sandbox Code Playgroud)

但在64位上,它必须改为

print (" my int: %ld\n", (long)myInt);
Run Code Online (Sandbox Code Playgroud)

我有两个相关的问题:

  1. 我的第一个想法是,当你告诉printf打印一个变量,给它一个格式时,它会查看该变量的地址并获取该格式所需的字节数.这一开始似乎是个大问题.例如,如果你有一个变量myChar,它是一个char(1个字节),但使用了%d的格式说明符,那将告诉printf转到myChar的地址并获取接下来的4个字节,将其视为int.如果是这种情况,似乎printf会从相邻变量中获取垃圾日期(因为它抓取了4个字节,但实际值只有1个字节).然而,情况似乎并非如此.通过使用myChar并指定%d,printf抓取1个字节,然后用0表示填充高3个字节.我的理解在这里是否正确?

  2. 如果上述情况属实,那么始终将变量提升到最大值是否有任何真正的危害,以避免在32/64位情况下出现的问题类型.例如,如果你有一个短变量myShort和一个int变量myInt,那么打印它们总是有任何缺点:

    printf("myShort%ld",(long)myShort); printf("myInt%ld",(long)myInt);

谢谢你的任何澄清.

Who*_*aig 6

关于printf:在您选择的情况下,"%d"必须按规范处理平台定义的"int"数据类型.无论是32位,64位还是128位线性AS/400值都无关紧要.如果要将值提升为更大的字段类型(并将该促销与相关格式字符串粒子匹配),您当然可以自由地这样做,

int a=0;
printf("%ld", (long)a);
Run Code Online (Sandbox Code Playgroud)

肯定是使用促销定义的行为.

我认为你的问题的真正关键在于以下情况,以及强制促销是否可以"解决"出现的任何问题.例如:

char ch = 'a';
printf("%d", ch);
Run Code Online (Sandbox Code Playgroud)

或者说:

char ch = 'a';
printf("%ld", (long)ch);
Run Code Online (Sandbox Code Playgroud)

或者这个(这是你似乎试图避免的真实情况):

char ch = 'a';
printf("%ld", ch);
Run Code Online (Sandbox Code Playgroud)

第一个将起作用,但这只是因为在va-arg列表中推送的任何堆栈的最小大小是平台大小int.编译器会自动将值提升为int.由于"%d"期望一个平台int都能很好地出现.

第二个将始终工作,并得到完全支持.有一个从一个明确的定义,并推广charlong.即使long是64位(或更大),它仍然可以工作.

第三个是UB.printf正在寻找一个long,只会出现一个字节int.如果这似乎在您的平台上"工作",那么检查您的平台宽度intlong.它可能"工作"只是因为你的平台longint位宽相同.当将代码移植到不是它们的平台时,它会带来有趣的惊喜,并且由于它是通过va-arg推送的,所以在真正的不同宽度进入游戏之前你不会看到它.

所有这一切,现在抛出一个实际的地址(某些东西,真的),如所需要的scanf,我们正在寻找完全不同的东西.

int val;
sscanf("%ld",&val);
Run Code Online (Sandbox Code Playgroud)

这是一个等待发生的seg-fault.就像上面一样,如果您的平台long和平台int宽度相同,您将永远不会知道它.将此代码放在一个不同大小的框中,longint为随后的核心文件的gdb加载做好准备.