【问题标题】:How come I am able to override printf in C language?为什么我能够用 C 语言覆盖 printf?
【发布时间】:2022-01-27 21:01:20
【问题描述】:

考虑下一段代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

int printf(const char *format, ...)
{
    va_list args;

    return 1;
}

int main()
{
    printf("Hello there");

    return 0;
}

确实,printf 什么也没打印。这意味着,编译器“更喜欢”这个函数而不是&lt;stdio.h&gt; 中声明的函数。但是C不允许函数覆盖,据我了解,它应该抛出一个冲突错误的错误。

谁能解释这种行为?

【问题讨论】:

  • 不是 C 的错。询问链接器。
  • 顺便说一句,如果你想以定义的方式替换printf,请用另一个名称定义你自己的版本,例如MyPrintf,然后在函数内部定义int (*printf)(const char * restrict,...) = MyPrintf .虽然 printf 保留用于文件范围或外部链接,但您可以将其用于您自己的目的,使用块范围而不是链接。但是,您必须在要使用它的每个函数中定义它。

标签: c


【解决方案1】:

C 标准说 (7.1.3 Reserved identifiers):

  • 以下任何子条款(包括未来的库方向)和 errno 中的所有具有外部链接的标识符始终保留用作具有外部链接的标识符。
  • 以下任何子条款(包括未来的库方向)中列出的每个具有文件范围的标识符都保留用作宏名称和在同一名称空间中作为具有文件范围的标识符,如果包括其任何关联的头文件.
  • 如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的除外),或将保留标识符定义为宏名称,行为未定义.

因此,当包含&lt;stdio.h&gt; 时,printf 在普通标识符的名称空间中被保留为具有文件范围的标识符。此外,printf 始终保留为具有外部链接的标识符,即使不包括 &lt;stdio.h&gt;

7.1.4 Use of library functions 不允许定义具有保留名称的函数。

在大多数实现中,这样的定义会默默地替换库函数,但标准不保证任何事情。

【讨论】:

    【解决方案2】:

    MSVC 编译失败。

    https://godbolt.org/z/Y1o14jj39

    答案是,在 Linux 上,链接器会首先尝试使用您的本地函数,然后才会在系统库中搜索该函数,并且由于各种历史原因,这不是错误。

    是的,printf 可以在多个库中定义,最后加载的库将具有优先权。这是一个特点!您可以通过将LD_PRELOAD 环境变量设置为使用该系统调用的您自己的共享库的路径来覆盖任何系统调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-03
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 2020-06-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多