我正在阅读Kernighan的C编程书,并且遇到了这个问题.两者之间的差异或他们各自的使用标准.我在StackOverflow上发现了一些处理此问题的帖子.我得到了答案的一部分,但理解它们有点麻烦.
正如他们在这里提到的(putc需要stdout,vs puts):
根据Kernighan的书,
putc它相当于fputc但putc可以作为宏实现,并且putc可以不止一次地评估它的流参数.
putc和之间的区别fputc是,通过使用putc,您冒着运行本质上不安全的宏版本的风险,因为它可能不得不多次评估其流参数.这导致大多数人不知道并且因此不注意的并发症,因此fputc更好地使用.fputc的宏没有这个问题.
问题:
putc可以作为一个宏实现但是同样的问题是什么fputc?
第二个声明提到了一些并发症和安全问题.那些是什么?
putc不止一次地评估它的论点.那么与评估论证相比,它带来了哪些优点或缺点.
Ada*_*eld 18
宏实现的问题在于,如果任何参数都有副作用,那么这些副作用可能会被多次评估,可能导致未定义的行为.考虑这个玩具示例:
#define SQUARE(x) ((x) * (x))
Run Code Online (Sandbox Code Playgroud)
大多数情况下,这将按预期运行,但如果你传入一个表达式f(),那么调用函数的副作用f()将发生两次,而不是一次,因为预处理器只是一个不知道C的文本转换器:
int f()
{
printf("f() was called\n");
return 42;
}
...
int x = SQUARE(f()); // This calls f() twice! It gets expanded to this:
// int x = (f() * f());
Run Code Online (Sandbox Code Playgroud)
为了正确看待这个问题putc,如果实现为宏,该stream函数可以多次评估其参数.所以,如果该流来自一个函数:
FILE *get_file()
{
// Potential side effects could happen here
return some_file;
}
...
putc('A', get_file());
Run Code Online (Sandbox Code Playgroud)
然后,这可能会导致函数get_file()被多次调用,可能会产生不必要的副作用.
当然,解决方案是只调用常规函数fputc()而不是putc().由于它不是一个宏,因此不会有多次评估其参数的任何潜在问题.有时候宏会很危险,所以要小心使用它们.