C++中如何处理可变参数(var_arg)多类型?及空指针解引用问题解决
C++可变参数多类型处理与空指针解引用问题修复
错误日志
10-08 17:26:00.835 5249 5617 D DigestGenerator: /apex/com.android.runtime/lib/bionic/libc.so!libc.so (strstr+) () 10-08 17:26:00.835 5249 5617 D DigestGenerator: XXbase.apk!libtest.so (test_bool(char const*)+) ()
问题代码
bool test_bool(const char *filename) { if (strstr(filename, "yes")) { return true; } return false; } long *test_long(long number, ...) { va_list args; va_start(args, number); for(int i=0; i<number; ++i) { if (test_bool(va_arg(args, const char *))) { //do something return 0; } } va_end(args); //do something return 0; } test_long(0, 1, "yes", 3);
问题根源
调用test_long时传入了整数、字符串等多种类型参数,但函数内部强制以const char*类型解析所有可变参数。当解析整数1和3时,会把整数数值当作指针地址,该地址大概率是无效的空指针或非法内存,传入strstr后触发空指针解引用错误。
可变参数多类型的正确处理方式
C++中传统C风格可变参数(va_list)本身不携带类型信息,要安全处理多类型参数,可采用以下方案:
显式标记参数类型:
在可变参数序列中加入类型标识,让函数能根据标识解析对应类型。示例:#include <cstdarg> #include <cstring> enum ArgType { INT, STRING }; bool test_bool(const char *filename) { if (filename && strstr(filename, "yes")) { // 先判空避免非法访问 return true; } return false; } long *test_long(long number, ...) { va_list args; va_start(args, number); for(int i=0; i<number; ++i) { ArgType type = static_cast<ArgType>(va_arg(args, int)); switch(type) { case INT: { long val = va_arg(args, long); // 处理整数逻辑 break; } case STRING: { const char* str = va_arg(args, const char*); if (str && test_bool(str)) { // do something va_end(args); return 0; } break; } } } va_end(args); // do something return 0; } // 调用时先传类型标识,再传参数 test_long(3, STRING, "yes", INT, 1, INT, 3);采用C++11及以上的可变模板:
利用模板参数包实现类型安全的可变参数处理,无需手动解析类型:#include <cstring> bool test_bool(const char *filename) { if (filename && strstr(filename, "yes")) { return true; } return false; } // 递归终止函数 long* process_args() { // 处理完所有参数后的逻辑 return 0; } // 处理字符串参数 template<typename... Args> long* process_args(const char* str, Args... args) { if (test_bool(str)) { // do something return 0; } return process_args(args...); } // 处理整数参数 template<typename... Args> long* process_args(long num, Args... args) { // 处理整数逻辑 return process_args(args...); } template<typename... Args> long* test_long(Args... args) { return process_args(args...); } // 直接传入任意类型参数,模板自动匹配处理 test_long(0, 1, "yes", 3);使用std::variant或std::any(C++17+):
将所有可变参数包装为std::variant或std::any,统一传入后再判断类型:#include <vector> #include <variant> #include <cstring> bool test_bool(const char *filename) { if (filename && strstr(filename, "yes")) { return true; } return false; } long* test_long(std::vector<std::variant<long, const char*>> args) { for (auto& arg : args) { if (std::holds_alternative<const char*>(arg)) { const char* str = std::get<const char*>(arg); if (test_bool(str)) { // do something return 0; } } else if (std::holds_alternative<long>(arg)) { long num = std::get<long>(arg); // 处理整数逻辑 } } // do something return 0; } // 调用时包装参数 test_long({0, 1, "yes", 3});
当前错误的紧急修复
如果暂时不想重构代码,至少要在test_bool中先判断指针有效性,避免空指针解引用:
bool test_bool(const char *filename) { // 先检查指针是否为空 if (!filename) { return false; } if (strstr(filename, "yes")) { return true; } return false; }
但这只是治标,根本解决还是要修复可变参数的类型解析逻辑。
内容的提问来源于stack exchange,提问作者vdTOG
相关产品推荐
相关产品推荐

