INF:Results Unpredictable w/ Multi va_arg() in Parameter List

ID Number: Q66738

5.10 6.00 6.00a 6.00ax 7.00 | 5.10 6.00 6.00a

MS-DOS | OS/2

Summary:

Because the order of expression evaluation is not always defined in C,

certain behavior depends strictly on the particular C implementation.

This is demonstrated by the sample program below, which shows the

unpredictable values passed to a function when the va_arg() macro is

used more than once in a function parameter list.

Sample Code

-----------

#include<stdio.h>

#include<stdarg.h>

void foo(int, ...);

void main(void)

{

foo(1, 2, 3, 4);

}

void foo(int first, ...)

{

va_list arg_ptr;

va_start(arg_ptr, first);

printf("%d %d %d %d\n",first, va_arg(arg_ptr, int),

va_arg(arg_ptr, int),

va_arg(arg_ptr, int));

}

When compiled under C version 5.1, the output is as follows:

1 4 3 2

When compiled under C version 6.0, 6.0a, C 6.0ax, or C/C++ version

7.0, the output is as follows:

1 4 4 4

More Information:

The va_arg() macro provides a way to access the arguments of a

function when the function takes a variable number of arguments. The

va_arg() macro returns a variable parameter by referencing the pointer

(arg_ptr) to the list of arguments and then incrementing this pointer

to point to the next variable argument. Thus, the values passed to the

printf() function in the above example depend on the order in which

the va_arg() macros are evaluated.

However, the C language does not guarantee the evaluation order of

most expressions, so code should never be written in a way that

depends on the evaluation order within an expression to proceed in a

particular manner. The output of the sample code above demonstrates

the undefined behavior and the unwanted side effects that may result

from this type of code just from compiling it under different versions

of the compiler.

To preserve the original order of the arguments in the sample above,

the va_arg() macro must be used only once in a single expression. One

method is to use a loop to call the va_arg() macro once every

iteration. The loop will process the variable arguments one by one and

stop when the last parameter is reached. This can be done by passing

an additional parameter as a flag to the function foo.

The following is a corrected version of the program where the

expressions are independent of evaluation order:

Corrected Sample Code

---------------------

#include<stdio.h>

#include<stdarg.h>

void foo(int, ...);

void main(void)

{

foo(1, 2, 3, 4, -1); /* using -1 as a flag */

}

void foo(int first, ...)

{

int temp;

va_list arg_ptr;

va_start(arg_ptr, first);

temp=first;

while(temp != -1) /* test for flag -1 */

{

printf("%d ", temp);

temp=va_arg(arg_ptr, int);

}

}

The output is as follows:

1 2 3 4

Additional reference words: 5.00 5.10 6.00 6.00a 6.00ax 7.00 S_QUICKC