gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 04:20:44 24 4
gpt4 key购买 nike

我构建了一个类似 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com