建设网站是普通办公吗,酒店平台网站建设,c2c模式是什么,前期的网站建设的难度C语言变长参数及其陷阱
C 工具
变长参数列表
这部分解释了旧的 C 风格变长参数列表。了解这些内容很重要#xff0c;因为你可能会在遗留代码中遇到它们。然而#xff0c;在新代码中#xff0c;你应该使用变参模板来实现类型安全的变长参数列表。
考虑 C 函数 printf()因为你可能会在遗留代码中遇到它们。然而在新代码中你应该使用变参模板来实现类型安全的变长参数列表。
考虑 C 函数 printf()来自 cstdio。你可以用任意数量的参数调用它
printf(int %d\n, 5);
printf(String %s and int %d\n, hello, 5);
printf(Many ints: %d, %d, %d, %d, %d\n, 1, 2, 3, 4, 5);C/C 提供了语法和一些实用宏用于编写你自己的变长参数函数。这些函数通常看起来很像 printf()。尽管你不经常需要这个特性但偶尔你会遇到它相当有用的情况。例如假设你想编写一个快速而简单的调试函数当设置了调试标志时该函数将字符串打印到 stderr但如果没有设置调试标志则不执行任何操作。就像 printf() 一样这个函数应该能够打印具有任意数量和任意类型参数的字符串。一个简单的实现如下
#include cstdio
#include cstdargbool debug { false };void debugOut(const char* str, ...) {va_list ap;if (debug) {va_start(ap, str);vfprintf(stderr, str, ap);va_end(ap);}
}首先请注意 debugOut() 的原型包含一个类型化且命名的参数 str后面跟着 ...省略号。它们代表任意数量和类型的参数。要访问这些参数你必须使用 cstdarg 中定义的宏。你声明一个 va_list 类型的变量并用 va_start 调用进行初始化。va_start() 的第二个参数必须是参数列表中最右边的命名变量。所有具有变长参数列表的函数都至少需要一个命名参数。debugOut() 函数简单地将这个列表传递给 vfprintf()cstdio 中的标准函数。vfprintf() 调用返回后debugOut() 调用 va_end() 来终止访问变量参数列表。在调用 va_start() 后你必须始终调用 va_end()以确保函数以一致的堆栈状态结束。你可以如下方式使用该函数
debug true;
debugOut(int %d\n, 5);
debugOut(String %s and int %d\n, hello, 5);
debugOut(Many ints: %d, %d, %d, %d, %d\n, 1, 2, 3, 4, 5);访问参数
如果你想自己访问实际参数你可以使用 va_arg() 来做到这一点。它接受 va_list 作为第一个参数以及要解释的参数的类型。不幸的是除非你提供明确的方式否则无法知道参数列表的结尾。例如你可以使第一个参数是参数数量的计数。或者在你有一组指针的情况下你可能需要最后一个指针是 nullptr。有许多方法但它们都对程序员来说是繁琐的。
下面的示例演示了调用者在第一个命名参数中指定提供了多少个参数的技术。该函数接受任意数量的 int 并打印出来
void printInts(size_t num, ...) {va_list ap;va_start(ap, num);for (size_t i { 0 }; i num; i) {int temp { va_arg(ap, int) };cout temp ;}va_end(ap);cout endl;
}你可以按以下方式调用 printInts()。请注意第一个参数指定将跟随多少个整数。
printInts(5, 5, 4, 3, 2, 1);为什么不应使用 C 风格的变长参数列表
访问风险
使用 C 风格的变长参数列表访问参数并不安全。这种方法存在几个风险从 printInts() 函数可以看出
不知道参数的数量在 printInts() 的情况下你必须信任调用者作为第一个参数传递正确数量的参数。在 debugOut() 的情况下你必须信任调用者在字符数组后传递的参数数量与字符数组中的格式化代码数量相同。不知道参数的类型va_arg() 接受一个类型用它来解释其当前位置的值。然而你可以告诉 va_arg() 将值解释为任何类型。它无法验证正确的类型。 警告避免使用 C 风格的变长参数列表。建议传递一个 std::array 或 vector 的值、使用初始化列表或者使用类型安全的变参模板来实现变长参数列表。