当前位置:首页 > 科技  > 软件

C 语言变长参数及其陷阱

来源: 责编: 时间:2023-12-05 09:25:47 434观看
导读C 工具变长参数列表这部分解释了旧的 C 风格变长参数列表。了解这些内容很重要,因为你可能会在遗留代码中遇到它们。然而,在新代码中,你应该使用变参模板来实现类型安全的变长参数列表。考虑 C 函数 printf(),来自 <cstdi

gSl28资讯网——每日最新资讯28at.com

C 工具

变长参数列表

这部分解释了旧的 C 风格变长参数列表。了解这些内容很重要,因为你可能会在遗留代码中遇到它们。然而,在新代码中,你应该使用变参模板来实现类型安全的变长参数列表。gSl28资讯网——每日最新资讯28at.com

考虑 C 函数 printf(),来自 <cstdio>。你可以用任意数量的参数调用它:gSl28资讯网——每日最新资讯28at.com

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() 一样,这个函数应该能够打印具有任意数量和任意类型参数的字符串。一个简单的实现如下:gSl28资讯网——每日最新资讯28at.com

#include <cstdio>#include <cstdarg>bool 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(),以确保函数以一致的堆栈状态结束。你可以如下方式使用该函数:gSl28资讯网——每日最新资讯28at.com

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。有许多方法,但它们都对程序员来说是繁琐的。gSl28资讯网——每日最新资讯28at.com

下面的示例演示了调用者在第一个命名参数中指定提供了多少个参数的技术。该函数接受任意数量的 int 并打印出来:gSl28资讯网——每日最新资讯28at.com

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()。请注意,第一个参数指定将跟随多少个整数。gSl28资讯网——每日最新资讯28at.com

printInts(5, 5, 4, 3, 2, 1);

为什么不应使用 C 风格的变长参数列表

访问风险

使用 C 风格的变长参数列表访问参数并不安全。这种方法存在几个风险,从 printInts() 函数可以看出:gSl28资讯网——每日最新资讯28at.com

  • 不知道参数的数量:在 printInts() 的情况下,你必须信任调用者作为第一个参数传递正确数量的参数。在 debugOut() 的情况下,你必须信任调用者在字符数组后传递的参数数量与字符数组中的格式化代码数量相同。
  • 不知道参数的类型:va_arg() 接受一个类型,用它来解释其当前位置的值。然而,你可以告诉 va_arg() 将值解释为任何类型。它无法验证正确的类型。

警告:避免使用 C 风格的变长参数列表。建议传递一个 std::array 或 vector 的值、使用初始化列表,或者使用类型安全的变参模板来实现变长参数列表。gSl28资讯网——每日最新资讯28at.com

gSl28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-38135-0.htmlC 语言变长参数及其陷阱

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 一次性讲清楚「连接池获取连接慢」的所有原因|

下一篇: 三分钟搞懂CUDA和GPU编程

标签:
  • 热门焦点
  • 帅气纯真少年!日本最帅初中生选美冠军出炉

    日本第一帅哥初一生选美大赛冠军现已正式出炉,冠军是来自千叶县的宗田悠良。日本一直热衷于各种选美大赛,从&ldquo;最美JK&rdquo;起到&ldquo;最美女星&r
  • 得物效率前端微应用推进过程与思考

    一、背景效率工程随着业务的发展,组织规模的扩大,越来越多的企业开始意识到协作效率对于企业团队的重要性,甚至是决定其在某个行业竞争中突围的关键,是企业长久生存的根本。得物
  • 多线程开发带来的问题与解决方法

    使用多线程主要会带来以下几个问题:(一)线程安全问题  线程安全问题指的是在某一线程从开始访问到结束访问某一数据期间,该数据被其他的线程所修改,那么对于当前线程而言,该线程
  • 使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 东方甄选单飞:有些鸟注定是关不住的

    作者:彭宽鸿来源:华尔街科技眼&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一
  • 小米汽车电池信息疑似曝光:容量101kWh,支持800V高压快充

    7月14日消息,今日一名博主在社交媒体发布了一张疑似小米汽车电池信息的照片,显示该电池包正是宁德时代麒麟电池,容量为101kWh,电压为726.7V,可以预测小
  • 余承东:AI大模型技术的发展将会带来下一代智能终端操作系统的智慧体验

    8月4日消息,2023年华为开发者大会(HDC.Together)今天正式开幕,华为发布HarmonyOS 4、全新升级的鸿蒙开发套件、HarmonyOS Next开发者预览版本等一系列
  • 电博会上海尔智家模拟500平大平层,还原生活空间沉浸式体验

    电博会为了更好地让参展观众真正感受到智能家居的绝妙之处,海尔智家的程传岭先生同样介绍了展会上海尔智家的模拟500平大平层,还原生活空间沉浸式体验。程传
Top