C编程printf格式搜索表达式 [英] c programming printf format searches expressions

查看:111
本文介绍了C编程printf格式搜索表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小问题. 我有这段代码:

#include <stdio.h>

int main(){
    printf("%d, %f, %d\n", 0.9, 10, 'C');
}

输出为:

10, 0.900000, 67

但我本来期望:

0, 10.0, 67

但是看起来printf在表达式中搜索相应的类型(将int和float都转换了) 有人可以帮我解决这个问题吗? 非常感谢你!

解决方案

但我本来期望:…

当格​​式字符串与顺序的参数类型不匹配时,则行为未定义.什么都可能发生.您不能期望任何东西(而且我不明白为什么会期望0.也许您期望printf使用格式字符串在浮点数和整数之间转换参数.只是没有.这是一个像您一样的可变参数函数可以编写自己的格式,并且格式字符串对尾随参数的类型进行编码的事实不用于转换它们.)

现代的调用约定将寄存器用于前几个参数,甚至对于可变参数函数也可以使用寄存器.在x86-64上,约定可以例如是始终可以在浮点寄存器xmm0中预期可变参数函数的第一个浮点参数,而整数参数则在通用寄存器%rdi中传递, %rsi%rdx,…的效果是printf("%f %d", 1, 1.0)打印浮点参数,后跟整数参数.

作为一个例子,这是一个简短的程序:

#include <stdio.h>

int main(){
  printf("%d, %f, %d\n", 0.9, 10, 'C');

  printf("%d, %f, %d\n", 10, 0.9, 'C');
}

这是我的编译器(在Mac OS X 10.6上为Clang)编译程序的方式:

leaq <memory location of format string>, %rbx

movq    %rbx, %rdi
movsd   <memory location of 0.9 constant>, %xmm0
movl    $10, %esi
movl    $67, %edx
movb    $1, %al
callq   _printf

movq    %rbx, %rdi
movl    $10, %esi
movsd   <memory location of 0.9 constant>, %xmm0
movl    $67, %edx
movb    $1, %al
callq   _printf

…

很明显,两个调用产生相同的结果.但是对于一种情况,这是偶然的,并且仅对于该特定的编译器版本和ABI是有效的",而另一种情况则遵循该标准,并且必须在任何地方都可以工作.

同样,printf("%d %f", 0.9, 10)是未定义的行为,在任何情况下都不应使用它.

I have a small question. I have this piece of code:

#include <stdio.h>

int main(){
    printf("%d, %f, %d\n", 0.9, 10, 'C');
}

And the output is this:

10, 0.900000, 67

But I would have expected:

0, 10.0, 67

But it looks like the printf searches for the corresponding type in the expressions (int and float are turned) Could anyone help me with this problem? Thank you very much!

解决方案

But I would have expected: …

When the format string does not match the types of the arguments in order, the behavior is undefined. Anything can happen. You cannot expect anything (and I do not see why you would expect 0. Maybe you expect printf to use the format string to convert the arguments between floating-point and integer. It just doesn't. It's a variadic function like you could write your own, and the fact that the format string encodes the types of the trailing arguments is not used to convert them).

Modern calling conventions use registers for the first few arguments, and can use registers even for variadic functions. On x86-64, the convention can be for instance that the first floating-point argument to a variadic function can always be expected in the floating-point register xmm0, whereas integer arguments are passed in general-purpose registers %rdi, %rsi, %rdx, … This has the effect that printf("%f %d", 1, 1.0) prints the floating-point argument followed by the integer argument.

As an illustration, here is a short program:

#include <stdio.h>

int main(){
  printf("%d, %f, %d\n", 0.9, 10, 'C');

  printf("%d, %f, %d\n", 10, 0.9, 'C');
}

This is how my compiler (Clang on Mac OS X 10.6) compiles the program:

leaq <memory location of format string>, %rbx

movq    %rbx, %rdi
movsd   <memory location of 0.9 constant>, %xmm0
movl    $10, %esi
movl    $67, %edx
movb    $1, %al
callq   _printf

movq    %rbx, %rdi
movl    $10, %esi
movsd   <memory location of 0.9 constant>, %xmm0
movl    $67, %edx
movb    $1, %al
callq   _printf

…

It is clear that the two calls produce the same result. But in the case of one, it is accidental and only "works" for this particular compiler version and ABI, whereas the other one respects the standard and has to work anywhere.

Again, printf("%d %f", 0.9, 10) is undefined behavior and you should not use it in any circumstances.

这篇关于C编程printf格式搜索表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆