0

I wrote below C program to call function with variable number of arguments.

#include<stdio.h>
#include<stdarg.h>

void display(int, int, ...);

int main()
{
    display(1,5,1,2,3,4,5);
    display(2,3,'A','B','C');
    printf("\n");
    return 0;
}

void display(int type, int tot_num, ...)
{
    int i, j;
    char c;

    va_list ptr;
    va_start (ptr, tot_num);

    switch(type)
    {
            case 1:
            for (j=0; j<tot_num; j++)
            {
                    i = va_arg (ptr, int);
                    printf("%d ",i);

            }
            break;

            case 2:
            for (j=0; j<tot_num; j++)
            {
                    c = va_arg(ptr, char);
                    printf("%c ",c);
            }
    }
}

However when I compile the program i get below warning from gcc.

-bash-4.1$ gcc varArg3.c
varArg3.c: In function âdisplayâ:
varArg3.c:41: warning: âcharâ is promoted to âintâ when passed through â...â
varArg3.c:41: note: (so you should pass âintâ not âcharâ to âva_argâ)
varArg3.c:41: note: if this code is reached, the program will abort
-bash-4.1$

Line 41 is c = va_arg(ptr, char);

When I read the man 3 page for va_arg it was mentioned as below:

If there is no next argument, or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), random errors will occur.

When I read this, I was thinking that c = va_arg(ptr, char); is correct because, the data in the variable argument list were characters . However above warning by gcc suggest that variable arguments passed are not really characters but integers.

As suggested by gcc, I change it to c = va_arg(ptr, int);, and now I get no warnings. Also I get expected output when I run the program.

So, were the characters (in second call to diplay() in main()) passed as integers to display() ?

Thanks.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
sps
  • 2,720
  • 2
  • 19
  • 38

1 Answers1

2

Yes type of 'A' is int, try this

printf("typeof('A') == typeof(int) -> %s\n", 
         (sizeof('A') == sizeof(int)) ? "YES" : "NO");

and check it yourself.

Edit:
According to Jonathan Leffler's comment the warning would be issued even if you did this

char a = 'A';

and then passed a, because it will be anyway promoted toint, so it means that

int arg = va_arg(ptr, int);

is always correct, the mentioned part of the standard in the comment says the following

§6.5.2.2

7. If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.

Community
  • 1
  • 1
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • 3
    But even if the extra arguments were `char a = 'A';` and `display(2, 3, a, a, a)`, the values would be passed as `int`, not `char`, because of _default argument promotions_ (6.5.2.2 Function calls, para 7 in the C11 standard). – Jonathan Leffler Feb 18 '15 at 23:26
  • @iharob yea checked it. But after that i had a question like , "If I pass a char to a function and store it in a **char** variable in called function, how is it possible ? int needs 4 bytes ? char has 1 byte ? " But I again thought, "hold on, chars are of 1 byte so they can take a value only upto 2 (pow)8 - 1 , so if I pass an integer of a value which i equal or less than 2(pow)8 - 1 , then of course I can store that in a **char** variable ." Is my understanding right ? – sps Feb 18 '15 at 23:42
  • @1Byn Yes, it's right. If you pass a larger value you will have problems though. But as long as the value only needs 1 byte, there will be no problem. – Iharob Al Asimi Feb 18 '15 at 23:49