c - 确保只将指针传递给可变参数函数

标签 c function pointers preprocessor variadic

我构建了一个类似 printf 的可变参数函数,用于在自定义 CPU 上进行日志记录。

为了确保我没有内存错误,我编写了函数,以便它只接受指针并处理它们。预处理器总是在 va 列表的末尾添加一个 NULL 指针,因此只要函数重新识别零指针,它就会返回。这样,我就可以确定我没有阅读列表。 我这样做是为了防止错误处理程序,它应该是一个安全的功能。无论用户向 va-list 中输入什么,都不应该以崩溃告终。

我现在唯一的问题是确保用户只能传递指向可变参数函数的指针,没有别的(除了不属于 va 列表的前两个参数)我的函数声明如下所示:

void LogNew( UINT LogClass, char* pMsg, ... );

和空终止:

#define LogNew(...) LogNew(__VA_ARGS__, 0)

有没有一种方法,也许是通过预处理器,来确保没有人使用按值调用而不是按引用调用。

提前致谢!

最佳答案

如果你想减少或防止错误格式的错误,我认为最好的办法是使用 fprintf。它是一个可变参数函数,因此不安全,但它是用 C 打印内容的方式,因此程序员熟悉它及其缺点。如果您的日志记录功能只是一个宏,例如:

enum {Fatal, Error, Warning, Info};

int maxlevel = Error;

#define logmsg(L, ...) if (L > maxlevel); else {        \
        if (L == Fatal) fprintf(stderr, "Fatal: ");     \
        if (L == Error) fprintf(stderr, "Error: ");     \
                                                        \
        fprintf(stderr, __VA_ARGS__);                   \
        fprintf(stderr, "\n");                          \
                                                        \
        if (L == Fatal) exit(1);                        \
    }                                                   \

您可以获得静态分析的好处,它会警告您格式/类型不匹配。在 clang/gcc 中,-Wformat-Wall 的一部分,将执行此操作。在 Visual Studio 中,您可以使用 /analyze。 (当日志记录被抑制时,您不会生成 va 列表。)

如果您滚动自己的可变参数函数并调用 vfprintf,您可以 detect bad format strings使用 clang/gcc format 属性或 Visual Studio 中的 _Printf_format_string_ 注释。

就是说,如果您所有的变量参数都是同一类型,则可以使用数组。如果你的编译器支持 C99 的 compound literals ,您可以使用宏将参数列表的可变部分转换为数组。

假设所有打印的参数都应该是 const char *。 (我知道这不是你想要的,但请耐心等待。)然后你可以实现一个打印函数,它可以接受任何正数的 C 字符串,如下所示:

void put(const char **s)
{
    while (*s) {
        fputs(*s++, stdout);
    }

    fputs("\n", stdout);
}

#define put(...) put((const char *[]){__VA_ARGS__, NULL})

然后像这样使用它:

put("Couldn't open \"", fn, "\".");
put("My name is ", (rand() % 2) ? "Igor" : "Tamara", ".");
put("");

您可以 extend this techniqueconst void *。我将代码隐藏在 Ideone 链接后面,因为使用 void 会使您丢失参数的类型信息。您的代码可能不会严重崩溃,因为指针应该指向某处,但是当您使用错误的格式时,您仍然会调用未定义的行为并获得垃圾输出。

(在对第一个答案的评论中,Lundin 指出将整数类型转换为指针是合法的。这不是所显示答案的缺陷,而是语言的缺陷。您也可以说 puts( 54) 并且只得到一个警告。)

关于c - 确保只将指针传递给可变参数函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47137818/

相关文章:

c - 如何知道链表是​​否被正确删除?

c - 在 C 中通过引用传递动态长度的二维结构数组

javascript - 无法将 "apply"陷阱设置为代理对象

javascript - jQuery - 反向操作

c - 如何将 char 'a' 设置为 char 指针数组?

c - 执行二进制文件时获取 "exec format error"

c - 如何在 C 应用程序中处理冲突的结构定义

c++ - 当我想修改指向常量整数的指针时,为什么我的编译器不显示错误?

c++ - 在一键回调函数中显示的opengl函数

arrays - 如何将向量的元素设置为指向数组数组中的第一个元素?