在C89中使用可变参数函数而不传递参数或最终参数?

2 c enums variadic-functions c89

假设我有一个可变函数foo(int tmp, ...),当调用foo函数时,我需要知道有多少个参数.我知道有两种方法可以找出有多少参数:

  1. 在调用foo时使用最后一个参数,比如-1,所以你的函数调用将是这样的:foo(tmp, 1, 2, 9, -1)当你在foo内部并且va_arg调用返回-1时你知道你已经读取了所有的函数参数

  2. 在foo中再添加一个参数,程序员将拥有参数总数,因此你可以像这样调用foo:foo(tmp, 5, 1, 2, 3, 4, 5)或者foo(tmp, 2, 7, 8)

我曾经遵循第一种方式,曾经有过以下错误.随着代码:

expr_of_type(expr, boolexpr_e, newtable_e, nil_e, -1)
Run Code Online (Sandbox Code Playgroud)

其中expr_of_type是一个可变参数函数,并检查expr(第一个参数)是否是以下类型之一(boolexpr_e或new_table_e或nil_e具有所有类型的枚举类型).我一个人意外地写道:

expr_of_type(expr, boolexpr_e, newtable_e, nil_e -1)
Run Code Online (Sandbox Code Playgroud)

我忘记了nil_e和-1之间的逗号,因为nil_e有一个枚举类型,nil_e - 1是一个有效的表达式,因为nil_e不是0,当试图获取expr_of_type参数时,给定的变量函数没有找到-1作为最后一个参数继续搜索创建一个花了我一些时间才发现的bug.

我也没有找到第二种方式,因为当从可变参数函数中添加或删除一个参数时,您需要更改包含总参数数量的参数.

在寻找更好的方法来使用/创建可变参数函数时,我找到了可变的宏,它可以解决我在使用第一种方式时遇到的错误.但是可变参数宏可用于C99标准.我一直在寻找一种在C89中使用/创建可变参数函数的更好方法.有任何想法吗?

jam*_*lin 6

通常,您仍然必须以某种方式传递参数计数,无论是通过标记值还是通过显式计数.

但是,您可以通过制作更好的哨兵来解决您的哨兵问题.这是扩展为负常量的预处理器宏应该用括号括起来的原因之一:

#define VARARG_SENTINEL (-1)
Run Code Online (Sandbox Code Playgroud)

然后nil_e VARARG_SENTINEL会生成编译错误.

使用enumconst int将使用:

enum { VARARG_SENTINEL = -1 };
Run Code Online (Sandbox Code Playgroud)

对于哨兵值使用符号常量也会因其他原因更好(更多自我记录,以后更容易更改基础值).

  • 不,它不会.如果你有`const int VARARG_SENTILEL = -1;`当你忘记一个逗号时,你会得到像这样的`nil_e VARARG_SENTINEL`,它会产生编译错误.当你使用`enum {VARARG_SENTINEL = -1};`时会发生同样的事情.在忘记逗号的情况下使用这两个解决方案,就像使用`number1 number2`(例如`2 3`)这是一个无效的表达式但是当我使用-1时,你会有`number - 1`这是一个有效的表达式. (2认同)