理想情况下,您应该生成一个 MCVE(最小、完整、可验证的示例)或 SSCCE(简短、自包含、正确的示例)——两个名称(和链接)用于相同的基本思想。
当我尝试重现该问题时,我创建了:
#include <stdio.h>
#undef putchar
int putchar(int c)
{
fprintf(stderr, "%s: 0x%.2X\n", __func__, (unsigned char)c);
return fputc(c, stdout);
}
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
return 0;
}
当在 Mac OS X 10.9.4 上使用 GCC 4.9.1 编译时-O2
,-O3
我的putchar
函数被调用:
$ gcc -g -O2 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Werror pc.c -o pc
$ ./pc <<< "abc"
putchar: 0x61
putchar: 0x62
putchar: 0x63
putchar: 0x0A
abc
$
代码中唯一可能与您相关的是#undef putchar
删除函数的宏覆盖。
为什么try1.c
不调用你的putchar()
函数
#include <stdio.h>
int
main(int argc, char *argv[])
{
putchar('a');
printf("hello\n");
return(0);
}
该函数putchar()
可能会被<stdio.h>
. 如果您希望确保调用函数,则必须取消定义宏。
如果您不取消定义宏,它将覆盖您所做的任何事情。因此,编写以下内容至关重要#undef putchar
(建议进行其他更改,但实际上不是强制性的):
#include <stdio.h>
#undef putchar
int main(void)
{
putchar('a');
printf("hello\n");
return(0);
}
请注意,这putchar()
是一个保留符号。虽然在实践中你会侥幸把它当作一个函数来使用,但如果你设法找到一个它不起作用的实现,你就没有理由抱怨。这适用于标准 C 库中的所有符号。因此,正式地,你应该使用类似的东西:
#include <stdio.h>
#undef putchar
extern int put_char(int c); // Should be in a local header
#define putchar(c) put_char(c) // Should be in the same header
int main(void)
{
putchar('a');
printf("hello\n");
return(0);
}
这允许您保持“使用”源代码不变(除了包括本地头文件——但您可能已经有一个可以使用)。您只需更改实现以使用正确的本地名称。(我不相信这put_char()
是一个好的名称选择,但我不喜欢my_
前缀,因为它是答案中的常见约定。)
ISO/IEC 9899:2011 §7.1.4 库函数的使用
除非在随后的详细说明中另有明确说明,否则以下每个陈述均适用:……</p>
Any function
declared in a header may be additionally implemented as a function-like macro defined in
the header, so if a library function is declared explicitly when its header is included, one
of the techniques shown below can be used to ensure the declaration is not affected by
such a macro. Any macro definition of a function can be suppressed locally by enclosing
the name of the function in parentheses, because the name is then not followed by the left
parenthesis that indicates expansion of a macro function name. For the same syntactic
reason, it is permitted to take the address of a library function even if it is also defined as
a macro.185) The use of #undef to remove any macro definition will also ensure that an
actual function is referred to. Any inv ocation of a library function that is implemented as
a macro shall expand to code that evaluates each of its arguments exactly once, fully
protected by parentheses where necessary, so it is generally safe to use arbitrary
expressions as arguments.186) Likewise, those function-like macros described in the
following subclauses may be invoked in an expression anywhere a function with a
compatible return type could be called.187)
185) This means that an implementation shall provide an actual function for each library function, even if it
also provides a macro for that function.
186) Such macros might not contain the sequence points that the corresponding function calls do.
187) Because external identifiers and some macro names beginning with an underscore are reserved,
implementations may provide special semantics for such names. For example, the identifier
_BUILTIN_abs
could be used to indicate generation of in-line code for the abs
function. Thus, the
appropriate header could specify
#define abs(x) _BUILTIN_abs(x)
for a compiler whose code generator will accept it.
In this manner, a user desiring to guarantee that a given library function such as abs
will be a genuine
function may write
#undef abs
whether the implementation’s header provides a macro implementation of abs
or a built-in
implementation. The prototype for the function, which precedes and is hidden by any macro
definition, is thereby revealed also.
Judging from what you observe, in one set of headers, putchar()
is not defined as a macro (it does not have to be, but it may be). And switching compilers/libraries means that now that putchar()
is defined as a macro, the missing #undef putchar
means that things no longer work as before.