Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

c - Use variadic functions in C89 without passing number of arguments or a final argument?

Let's say I have a variadic function foo(int tmp, ...), when calling foo function I need to know how many arguments there are. I'm aware of two ways of finding out how many arguments there are:

  1. Use a final argument when calling foo, like -1, so your function call will be like this: foo(tmp, 1, 2, 9, -1) and when you are inside foo and a va_arg call returns -1 you know you have read all the function arguments

  2. Add one more argument in foo where the programmer will have the total number of arguments, so you will have calls to foo like this: foo(tmp, 5, 1, 2, 3, 4, 5) or foo(tmp, 2, 7, 8)

I used to follow the first way and once had the following bug. With the code:

expr_of_type(expr, boolexpr_e, newtable_e, nil_e, -1)

where expr_of_type was a variadic function and was checking if expr(the first argument) was one of the following types (boolexpr_e or new_table_e or nil_e had all type of an enumerated type). I one accidently wrote:

expr_of_type(expr, boolexpr_e, newtable_e, nil_e -1)

I forgot the comma between nil_e and -1, because nil_e had an enumerated type, nil_e - 1 was a valid expression and because nil_e was not 0 the given variadic function when trying to get expr_of_type arguments didn't find -1 as last argument and continued searching creating a bug which took me some time to find out.

I don't find the second way nice either, because when adding or removing one more argument from a variadic function you need to change the parameter that contains the number of total arguments.

In searching for a better way to use/create variadic functions I found variadic macros which can solve the bug I had when using the first way. But variadic macros are available to C99 standard. I was looking for a better way to use/create variadic functions in C89. Any ideas?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In general, you must still pass along the argument count somehow, whether via a sentinel value or via an explicit count.

You could, however, fix your sentinel problem by making a better sentinel. This is one of the reasons why preprocessor macros that expand to negative constants should be surrounded in parentheses:

#define VARARG_SENTINEL (-1)

Then nil_e VARARG_SENTINEL will generate a compilation error.

Using enum or const int would work too:

enum { VARARG_SENTINEL = -1 };

Using a symbolic constant for the sentinel value would be better for other reasons too (more self-documenting, easier to change the underlying value later).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share

2.1m questions

2.1m answers

63 comments

56.7k users

...