提问人:jeaq 提问时间:1/24/2023 最后编辑:Jabberwockyjeaq 更新时间:1/25/2023 访问量:223
C 格式说明符的意义何在?
What is the point of format specifier in C?
问:
如果我们在 printf 之前设置了变量的类型,那么 C 中格式说明符的意义何在?
例如:
#include<stdio.h>
int main(void)
{
int a=7
printf("%d", a);
}
就像,它已经准备好了,它是什么,它是整数(int)。那么,添加 %d 来指定它是一个整数有什么意义呢?
答:
printf()
接受可变数量的参数。要处理这些变量参数,它 () 需要知道最后一个固定参数是。它 () 还需要知道每个参数的类型,以便计算要读取的数据量。va_start()
va_arg()
格式说明符也是一个紧凑的模板(或 DSL),用于表示文本和变量的格式设置方式,包括字段宽度、对齐方式、精度、编码。
评论
int
int
sqrt(4.0)
4.0
printf()
writeln
printf
a
int
printf
添加以指定它是一个整数有什么意义?
%d
printf()
是一个函数,它在格式参数之后接收各种类型的可变数量的参数。它不直接知道传递或接收的参数的数量或类型。
调用方知道它给出的参数计数和类型。printf()
为了传递参数计数和类型信息,调用方使用 format 参数对参数计数和类型进行编码。 使用该格式并对其进行解码,以了解参数计数和类型。传递的格式和后续参数保持一致非常重要。printf()
这个问题的答案只有在C的历史背景下才有意义。
到目前为止,C 语言是一种非常古老的语言。虽然它无疑是一种“高级语言”,但它是出了名的低级语言。而它最早的编译器是刻意的、自觉的、小而简单的。
在它的第一个化身中,C 在函数调用期间没有强制执行类型安全。例如,如果你调用了 ,你得到了错误的答案,因为需要一个 类型的参数,但是一个 .程序员有责任使用正确类型的参数调用函数:编译器不知道(甚至没有尝试跟踪)每个函数所需的参数,因此它没有也不能执行自动转换。(一个单独的程序 lint
可以检查函数是否使用正确的参数调用。sqrt(144)
sqrt
double
144
int
C++ 通过引入函数原型纠正了这一缺陷。这些在1989年的第一个ANSI C标准中被C继承。但是,函数原型仅适用于需要单个固定参数列表的函数,这意味着它无法帮助接受可变数量参数的函数,首要示例是: .printf
要记住的另一件事是,在 C 中,它或多或少是一个普通的函数。(“普通”,除了接受可变数量的参数。因此,编译器没有直接的机制来通知参数的类型,并使该类型列表可供 printf 使用。 在运行时无法知道在任何给定调用期间传递了哪些类型;它只能依赖(必须依赖)格式字符串中提供的线索。(这与许多语言形成鲜明对比,其中许多语言的语句是编译器解析的语言的显式部分,这意味着编译器可以执行任何需要做的事情,以便根据其已知类型正确处理每个参数。printf
printf
print
因此,根据语言的规则(受向后兼容性和语言历史的约束),编译器不能对调用中的参数执行任何特殊操作,只能执行所谓的默认参数提升。因此,如果您编写类似printf
int a = 7;
printf("%f", a);
诚然,这是一个令人不舒服的情况。如今,程序员已经习惯了函数原型提供的保护和隐式提升。如果,这些天,你可以打电话
int x = sqrt(144);
让正确的事情发生,你为什么不能同样打电话
printf("%f\n", 144);
好吧,你不能,尽管一个好的、现代的编译器无论如何都会试图帮助你。尽管编译器不必检查格式字符串(因为这是在运行时要完成的工作),并且不允许编译器插入任何隐式转换(默认提升除外,这在这里没有帮助),但编译器可以复制 的逻辑,检查格式字符串,并在程序员出错时发出强烈警告。例如,给定printf
printf
printf("%f\n", 144);
GCC 打印“警告:格式 '%F' 需要类型为'double'的参数,但参数 2 的类型为'int',而 clang 打印”警告:format 指定类型'double',但参数类型为'int'”。
在我看来,这是一个很好的折衷方案,平衡了 C 的传统行为和现代的期望。
评论
上一个:我应该在这里使用什么格式说明符?
下一个:格式说明符是否执行隐式类型转换?
评论
printf
printf
int
double
char *
printf
a
int
7
printf
print
printf
printf
printf