printf的原型和实现

问题描述 投票:2回答:4

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

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

另外,该功能是如何实现的?如果它太复杂,我只想知道它在内部的工作原理。

c variadic-functions
4个回答
5
投票

如何声明printf函数

printf是一个variadic function,它自C99以来宣布如下:

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

...或省略号表示存在可变数量的参数,我们将使用va_start,va_arg,va_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); 
}

0
投票

printf的原型是:

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

此功能(参数...)称为变量参数函数。你也可以在stdarg.h的帮助下做到这一点。

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


0
投票

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

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

0
投票

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

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

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

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

请注意C ++所需的extern "C" {}事物,以防止C ++编译器从name-mangling中获取函数名称。请参阅上面的注释代码,了解我使用和测试的所有编译命令。另外请注意,打印“真实”的东西只是为了踢,因为我正在测试一些东西。

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 你好,世界 `true == 1`? = 1,`true == 1`? =真

© www.soinside.com 2019 - 2024. All rights reserved.