【问题标题】:Prototype of printf and implementationprintf的原型和实现
【发布时间】:2019-03-28 02:37:12
【问题描述】:

我开始想知道printf 函数是如何声明的,它总是接收一个字符串作为第一个参数(嗯,const char*),然后其余参数可以是多种类型,数量不定并以不同的顺序给出。

这是否意味着printf 函数被声明并覆盖了每种可能性?这对我来说没有多大意义,所以它真的像这样工作还是完全不同?

另外,这个功能是怎么实现的?如果它太复杂,我只想知道它在内部一般是如何工作的。

【问题讨论】:

  • 请注意,printf 是在 stdio.h 中声明的,这是您系统上可以打开并查看的实际文件。

标签: c variadic-functions


【解决方案1】:

printf 函数是如何声明的

printfvariadic function,它从 C99 开始声明如下:

​int printf( const char *restrict format, ... );
                                         ^^^

... 或省略号表示参数数量可变,我们将使用 va_startva_argva_end 宏和 va_list 类型以访问参数。

功能是如何实现的?

上面链接的文档中给出了一个非常简单的 printf 示例,如下所示,并修改为在 C 中工作:

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

void simple_printf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);

    while (*fmt != '\0') {
        if (*fmt == 'd') {
            int i = va_arg(args, int);
            printf( "%d\n", i ) ;
        } else if (*fmt == 'c') {
            int c = va_arg(args, int);
            printf( "%c\n", (char)c ) ;
        } else if (*fmt == 'f') {
            double d = va_arg(args, double);
            printf( "%f\n", d ) ;
        }
        ++fmt;
    }

    va_end(args);
}

int main()
{
    simple_printf("dcff", 3, 'a', 1.999, 42.5); 
}

【讨论】:

  • @YuHao 谢谢,已修复,cppreference 通常匹配C 文件,我搞糊涂了。
  • 哈哈,实现simple_printfprintf =)。我实际上想知道printf家庭使用的转换功能是否可以访问,对于scanf,有ato[fli]之类的东西,但反过来......我找不到它。
  • @luk32 这只是为了演示它是如何工作的,原来的 C++ 示例看起来不那么愚蠢,因为它使用了std::cout,但在功能上并没有真正的不同。
【解决方案2】:

printf的原型是:

int printf(const char *restrict format, ...);

这个特性(参数...)被称为变量参数函数。你也可以在stdarg.h 的帮助下做到这一点。

这是一个开始:C FAQ: Variable-Length Argument Lists

【讨论】:

    【解决方案3】:

    每个标准库都有相应的头文件,其中包含该库中所有函数的函数原型以及函数所需的各种数据类型和常量的定义。 printf 的标头是 &lt;stdio.h&gt;,其中包括其原型

    int printf( const char *restrict format, ... );
    

    【讨论】:

      【解决方案4】:

      这是一个俗气的小程序,它显示printf 的原型是:

      int printf ( const char * format, ... );
      

      (并且它不需要 restrict 其他人所示的关键字)。

      注意这里的printf 可以在不包括其他需要的stdio.h 头文件的情况下使用。这是因为简单地为 printf 函数声明一个 prototype 通过告诉编译器这个函数原型确实存在来让编译器高兴,并且因为 printf 的定义(实现)的目标代码也恰好存在于其他地方,链接器在链接时很高兴,在编译后。

      但是,请注意 C++ 所需的 extern "C" {} 东西,以防止 C++ 编译器使用 name-mangling 函数名称。有关我使用和测试的所有编译命令,请参见代码上方的 cmets。还要注意,打印“真实”的东西只是为了好玩,因为我正在测试一些东西。

      hello_world.c

      /*
      hello_world
      
      Gabriel Staples
      www.ElectricRCAircraftGuy.com
      27 Mar. 2019 
      
      Examples of how to compile & run:
      - NB: c90 requires C-style comments (slash star, star slash) and does NOT work with modern
            C++-style // comments!
        C:
          gcc -Wall -o hello_world hello_world.c && ./hello_world
          gcc -Wall -std=c90 -o hello_world hello_world.c && ./hello_world
          gcc -Wall -std=c99 -o hello_world hello_world.c && ./hello_world
          gcc -Wall -std=c11 -o hello_world hello_world.c && ./hello_world
        C++:
          g++ -Wall -o hello_world hello_world.c && ./hello_world
          g++ -Wall -std=c++98 -o hello_world hello_world.c && ./hello_world
          g++ -Wall -std=c++03 -o hello_world hello_world.c && ./hello_world
          g++ -Wall -std=c++11 -o hello_world hello_world.c && ./hello_world
      
      
      */
      
      // #include <stdio.h>   // for printf
      #include <stdbool.h> // for `true` and `false`
      
      #ifdef __cplusplus
      extern "C" {
      #endif
      int printf ( const char * format, ... ); // a hacky alternative to including stdio.h above! 
      #ifdef __cplusplus
      }
      #endif
      
      int main(void)
      {
          printf("Hello World\n");
          printf("`true == 1`? = %i, `true == 1`? = %s\n", true, (true == 1 ? "true" : "false"));
      
          return 0;
      }
      

      样本输出:

      $ gcc -Wall -o hello_world hello_world.c && ./hello_world
      你好世界
      `真 == 1`? = 1,“真 == 1”? =真

      【讨论】:

        猜你喜欢
        • 2019-09-21
        • 1970-01-01
        • 1970-01-01
        • 2011-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-14
        • 2011-04-01
        相关资源
        最近更新 更多