我正在摆弄 C 中的可变参数函数来了解它们是如何工作的,并且正在尝试构建一个简单的“打印行”函数,而不需要手动计算行数。我通过将函数包装在一个宏中来实现此目的,该宏将空指针添加到char *参数列表的末尾,以便该函数可以逐行打印,直到找到空参数。
我知道我已经避免了一些常见的陷阱,例如忘记在参数列表中强制转换空指针,但无论出于何种原因,该代码仍然无法正常工作。使用任意数量的参数调用该函数都会正确打印它们,然后无法检测空值,打印一堆垃圾数据,然后崩溃。
int printline(const char *str) {
printf("%s\n", str);
}
#define printlines(...) _comments(__VA_ARGS__, (char*)0)
int _printlines(char* first, ...) {
if (first) {
printline(first);
va_list ptr;
va_start(ptr, first);
char *next;
do {
char *next = va_arg(ptr, char *);
if (next) {
printline(next);
}
} while(next);
va_end(ptr);
}
}
int main() {
printlines("hi");
//prints 'hi', then prints garbage data and crashes
printlines("how", "are", "you");
//prints 'how', 'are', and 'you', then prints garbage data and crashes
_printlines("help", (char *)0);
//prints 'help', then prints garbage data and crashes
_printlines("something", "is", "wrong", (char *)NULL);
//prints 'something', 'is', and 'wrong', then prints garbage data and crashes
}
Run Code Online (Sandbox Code Playgroud)
如果你看一下这个:
char* next;
do{
char* next = va_arg(ptr,char*);
if(next){ comment(next); }
}while(next);
Run Code Online (Sandbox Code Playgroud)
您将看到有两个名为 的独立变量next,其中do..while循环内部的变量掩盖了外部定义的变量。您将 的结果分配va_arg给内部next. 然后,当您得到while (next)条件时,内部next超出范围,您现在正在读取next从未写入的外部。这会触发未定义的行为。
相反,你想要:
char* next;
do{
next = va_arg(ptr,char*);
if(next){ comment(next); }
}while(next);
Run Code Online (Sandbox Code Playgroud)
这样您就只有一个名为next您正在使用的变量。