【问题标题】:Printf-like function with optional format string argument and GCC format type-checking具有可选格式字符串参数和 GCC 格式类型检查的类 Printf 函数
【发布时间】:2012-09-12 12:51:58
【问题描述】:

我创建了一个类似printf 的函数,它接受以下参数:

  • 一个强制参数(自定义错误代码)
  • 可选格式字符串
  • 格式参数的可变计数

函数原型如下:

int my_printf(int err_code, ...);

err_code 还包括是否给出格式字符串(和可能的格式标签)的信息。

如果给定它们,我可以使用va_arg 函数提取格式字符串并将其与其余参数一起传递给vfprintf

调用看起来像:

my_printf(-ERR_SIMPLE);
my_printf(-ERR_COMPLICATED, "Error: problem with %d", 123);

很遗憾,我无法使用 GCC 属性进行格式类型检查,因为它需要 string-index

格式(原型、字符串索引、首先检查)

仍然可以进行类型检查吗? 使用辅助宏、辅助函数、修改可选格式字符串部分等的解决方案是可以接受的。

更新: 我不确定是否可以将修改后的va_list 传递给vfprintf 类函数。见 cmets。 如果可能的话,最好避免这种情况,并为可选的格式字符串部分使用宏或其他东西。

【问题讨论】:

  • 你的函数到底是如何工作的?如何从 valist 中去除格式字符串参数?
  • @KerrekSB 我用 const char *fmt = va_arg(args, const char *); 得到格式字符串。然后我可以简单地调用 vfprintf(stdout, fmt, args);
  • 那不是UB吗?我敢肯定,如果您已经开始胡思乱想,您将无法将 valist 传递给函数...
  • @KerrekSB 我不确定。它似乎适用于 x86 上的 GCC 4.4.5。我想我应该避免这种情况。但是,该问题仍然有效(并且已更新)。
  • 好吧,如果我们已经在该领域或可怕的黑客攻击,我不会太担心获得正确的属性:-)

标签: c gcc printf


【解决方案1】:

(抱歉,我没有看到您尝试过使用__attribute__。我的错)。

您可以尝试使用此处所述的“参数计数”:

http://locklessinc.com/articles/overloading/

我不知道这是否会导致 GCC 选择性地应用参数检查;但我认为应该。

更新它似乎正在工作,并添加了#define hack:

#include <stdio.h>

int printf_1(int err)
{
        printf("Got error %d\n", err);
        return 0;
}

int printf_2(int error, char *string)
{
        printf("Error %d and message %s\n", error, string);
        return 0;
}

int printf_3(int error, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));

int printf_3(int error, char *fmt, ...)
{
        printf("Received full string err=%d, fmt=%s\n", error, fmt);
        return 0;
}

#define printf_4        printf_3
#define printf_5        printf_3
#define printf_6        printf_3
#define printf_7        printf_3
#define printf_8        printf_3
#define printf_9        printf_3
#define printf_10       printf_3


#define COUNT_PARMS2(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _, ...) _
#define COUNT_PARMS(...)\
        COUNT_PARMS2(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

#define CAT(A, B) CAT2(A, B)
#define CAT2(A, B) A ## B

#define myprintf(...)\
        CAT(printf_, COUNT_PARMS(__VA_ARGS__))(__VA_ARGS__)

int main()
{
        myprintf(19);
        myprintf(19, "Hello");
        myprintf(19, "Hello '%s'", "world");
        // Warning!
        myprintf(19, "Hello '%s'", "world", 42);
        myprintf(19, 42);
        return 0;
}

我正确接收(gcc 4.6.2):

$ gcc -W -Wall -o test test.c

test.c: In function ‘main’:
test.c:48:2: warning: too many arguments for format [-Wformat-extra-args]
test.c:49:2: warning: passing argument 2 of ‘printf_2’ makes pointer from integer without a cast [enabled by default]
test.c:9:5: note: expected ‘char *’ but argument is of type ‘int’

【讨论】:

    猜你喜欢
    • 2020-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 2017-08-04
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    相关资源
    最近更新 更多