简体   繁体   English

C 中的格式说明符有什么意义?

[英]What is the point of format specifier in C?

What is the point of format specifier in C if we have allready set the type of variable before printf?如果我们已经在 printf 之前设置了变量类型,那么 C 中的格式说明符有什么意义呢?

For example:例如:

#include<stdio.h>
int main(void)
{
    int a=7
    printf("%d", a);
} 

Like, it's allready stated what a is, it's integer(int).就像,它已经说明了 a 是什么,它是 integer(int)。 So what is the point of adding %d to specify that it's an integer?那么添加 %d 以指定它是 integer 有什么意义呢?

The answer to this question really only makes sense in the context of C's history.这个问题的答案真的只有在 C 的历史背景下才有意义。

C is, by now, a pretty old language.到目前为止,C 是一种相当古老的语言。 Though undoubtedly a "high level language", it is famously low-level as high-level languages go. And its earliest compiler was deliberately and self-consciously small and simple.虽然毫无疑问是一种“高级语言”,但它与高级语言 go 一样是低级的。而且它最早的编译器有意且自觉地小巧简单。

In its first incarnation, C did not enforce type safety during function calls.在其第一个版本中,C 在 function 调用期间没有强制执行类型安全。 For example, if you called sqrt(144) , you got the wrong answer, because sqrt expects an argument of type double , but 144 is an int .例如,如果您调用sqrt(144) ,您会得到错误的答案,因为sqrt需要一个double类型的参数,但144是一个int It was the programmer's responsibility to call a function with arguments of the correct types: the compiler did not know (did not even attempt to keep track of) the arguments expected by each function, so it did not and could not perform automatic conversions.程序员有责任用正确类型的 arguments 调用 function:编译器不知道(甚至没有尝试跟踪)每个 function 期望的 arguments,因此它没有也不能执行自动转换。 (A separate program, lint , could check that functions were called with the correct arguments.) (一个单独的程序lint可以检查是否使用正确的 arguments 调用了函数。)

C++ corrected this deficiency, by introducing the function prototype . C++ 通过引入function 原型纠正了这个缺陷。 These were inherited by C in the first ANSI C standard in 1989. However, a function prototype only works for a function that expects a single, fixed argument list, meaning that it can't help for functions that accept a variable number of arguments, the premier example being: printf .这些在 1989 年的第一个 ANSI C 标准中由 C 继承。但是,function 原型仅适用于期望单个固定参数列表的 function,这意味着它无法帮助接受可变数量 arguments,首要的例子是: printf

The other thing to remember is that, in C, printf is a more or less ordinary function. ("Ordinary" other than accepting a variable number of arguments, that is.) So the compiler has no direct mechanism to notice the types of the arguments and make that list of types available to printf. printf has no way of knowing, at run time, what types were passed during any given call;另一件要记住的事情是,在 C 中, printf是一个普通的 function。(“普通”除了接受可变数字 arguments,即。)所以编译器没有直接的机制来注意类型arguments 并使该类型列表可供 printf 使用printf在运行时无法知道在任何给定调用期间传递了哪些类型; it can only rely (it must rely) on the clues provided in the format string.它只能依赖(必须依赖)格式字符串中提供的线索。 (This is by contrast to languages, many of them, where the print statement is an explicit part of the language parsed by the compiler, meaning that the compiler can do whatever it needs to do in order to treat each argument properly according to its known type.) (这与许多语言形成对比,其中print语句是编译器解析的语言的显式部分,这意味着编译器可以做任何它需要做的事情,以便根据其已知的正确处理每个参数类型。)

So, by the rules of the language (which are constrained by backwards compatibility and the history of the language), the compiler can't do anything special with the arguments in a printf call, other than performing what is called the default argument promotions .因此,根据语言规则(受向后兼容性和语言历史的限制),编译器不能对printf调用中的 arguments 执行任何特殊操作,除了执行所谓的默认参数提升 So the compiler can't fix things (can't perform the "correct" implicit conversion) if you write something like所以编译器不能修复问题(不能执行“正确的”隐式转换)如果你写类似

int a = 7;
printf("%f", a);

This is, admittedly, an uncomfortable situation.诚然,这是一种令人不安的情况。 These days, programmers are used to the protections and the implicit promotions provided for by function prototypes.如今,程序员已经习惯了 function 原型提供的保护和隐式提升。 If, these days, you can call如果,这些天,你可以打电话

int x = sqrt(144);

and have the right thing happen, why can't you similarly call让正确的事情发生,为什么你不能同样地打电话

printf("%f\n", 144);

Well, you can't, although a good, modern compiler will try to help you out anyway.好吧,你不能,尽管一个好的现代编译器无论如何都会尽力帮助你。 Although the compiler doesn't have to inspect the format string (because that's printf 's job to do, at run time), and the compiler isn't allowed to insert any implicit conversions (other than the default promotions, which don't help here), a compiler can duplicate printf 's logic, inspect the format string, and issue strong warnings if the programmer makes a mistake.虽然编译器不必检查格式字符串(因为这是printf的工作,在运行时),并且不允许编译器插入任何隐式转换(默认提升除外,它不会help here),编译器可以复制printf的逻辑,检查格式字符串,并在程序员出错时发出强烈警告。 For example, given例如,给定

printf("%f\n", 144);

gcc prints "warning: format '%f' expects argument of type 'double', but argument 2 has type 'int", and clang prints "warning: format specifies type 'double' but the argument has type 'int'". gcc 打印“警告:格式‘%f’需要‘double’类型的参数,但参数 2 的类型为‘int’”,而 clang 打印“警告:格式指定类型‘double’但参数的类型为‘int’”。

In my opinion, this is a fine compromise, balancing C's legacy behavior with modern expectations.在我看来,这是一个很好的妥协,平衡了 C 的遗留行为与现代期望。

printf() accepts a variable number of arguments. To process those variable arguments it ( va_start() ) needs to know the last fixed argument is. printf()接受变量 arguments。要处理这些变量 arguments,它 ( va_start() ) 需要知道最后一个固定参数是。 It ( va_arg() ) also needs to know the type of each argument so it figure how much data to read.它 ( va_arg() ) 还需要知道每个参数的类型,以便计算要读取的数据量。

The format specifier is also a compact template (or DSL) to express how text and variables should be formatted including field width, alignment, precision, encoding.格式说明符也是一个紧凑的模板(或 DSL),用于表达文本和变量的格式,包括字段宽度、alignment、精度、编码。

what is the point of adding %d to specify that it's an integer?添加%d以指定它是 integer 有什么意义?

printf() is a function which receives a variable number of arguments of various type after the format argument. printf()是一个 function,它在格式参数后接收各种类型的变量 arguments。 It does not directly know the number nor the type of arguments passed nor received.它不直接知道传递或接收的 arguments 的数量或类型。

The callers knows the argument count and types it gives to printf() .调用者知道它提供给printf()的参数计数和类型。

To pass the arguments count and type information, the format argument is used by the caller to encodes the argument count and types.要传递 arguments 计数和类型信息,调用者使用格式参数对参数计数和类型进行编码。 printf() uses that format and decodes it to know the argument count and type. printf()使用该格式并将其解码以了解参数计数和类型。 It is very important that the format and following arguments passed are consistent.很重要的一点是格式和后面传的arguments保持一致。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM