Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Confusion with stdarg

2 views
Skip to first unread message

Mac A. Cody

unread,
Jan 3, 2005, 1:58:05 AM1/3/05
to
Hello,

I'm encountering a problem with using stdarg that I cannot
figure out. I'm trying to develop a function for a linux
driver module that takes a variable-length sequence of
u8-type values. Below is the function:

#include <stdarg.h>
.
.
.
63 int sn9c102_write_va_regs(struct sn9c102_device* cam,
u16 index, int len, ...)
64 {
65 int res, i;
66 u8 data[32];
67 va_list args;
68
69 va_start(args, len);
70 for (i = 0; i < len; i++) {
71 data[i] = va_arg (args, u8);
72 }
73 va_end(args);
74 res = sn9c102_write_regs(cam, index, data, len);
75 if (res < 0) {
76 DEBUG(3, "Failed to write registers starting at index "
77 "0x%02X, error %d)", index, res)
78 return -1;
79 }
80 return 0;
81 }

When I compile the code, I get the following message:

sonix_pas202b.c: In function `sn9c102_write_va_regs':
sonix_pas202b.c:74: warning: implicit declaration of function
`sn9c102_write_regs'
sonix_pas202b.c:71: warning: `u8' is promoted to `int' when passed
through `...'sonix_pas202b.c:71: warning: (so you should pass `int' not
`u8' to `va_arg')

Why does the warning on line 71 occur? I believe that 'u8'
is typedef'ed somewhere in the linux kernel headers as an
'unsigned char', though I have not verified that yet. Is
there a way of telling 'va_arg' the actual type of 'u8'?

I'm compiling with GCC version 3.2.3 on Slackware Linux 9.1
(kernel 2.4.22).

Thanks,

Mac Cody

jacob navia

unread,
Jan 3, 2005, 2:01:40 AM1/3/05
to
Since the compiler didn't see the prototype of the function
it will promote u8 to int, and warns you about it.

Always prototype the functions before calling them, specially
when writing an OS!

Mac A. Cody

unread,
Jan 3, 2005, 2:11:50 AM1/3/05
to

Jacob,

Thanks for the quick response! Since the linux kernel headers
are included (I just didn't show them.) and the compiler does
not otherwise balk at the 'u8' typing (as on line 64 in the
code above), the compiler must be seeing a prototype somewhere
along the way (doesn't it?). Maybe I'm missing something here.

Thanks again,

Mac

Michael Mair

unread,
Jan 3, 2005, 2:23:57 AM1/3/05
to

Yes. Variable arguments of vararg functions get promoted, i.e. you
cannot pass just a char but will always get an int. That is, you
(necessarily) pass the u8 values as int values -- and have to retrieve
them as such. The same happens to functions without prototypes.
Something else: You should check against a buffer overrun of data
in the loop l70 -- l72.


Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.

Jack Klein

unread,
Jan 3, 2005, 2:40:11 AM1/3/05
to
On Mon, 03 Jan 2005 00:58:05 -0600, "Mac A. Cody"
<mac...@castcom.net> wrote in comp.lang.c:

> Hello,
>
> I'm encountering a problem with using stdarg that I cannot
> figure out. I'm trying to develop a function for a linux
> driver module that takes a variable-length sequence of
> u8-type values. Below is the function:
>
> #include <stdarg.h>
> .
> .
> .
> 63 int sn9c102_write_va_regs(struct sn9c102_device* cam,
> u16 index, int len, ...)

You can't pass unsigned characters as part of the "..." arguments to
variadic functions. You can't pass any of the character types, or
signed or unsigned short, or floats. The arguments to such functions,
after the fixed ones, undergo the default promotions.

See section 15 on functions with variable argument lists in the FAQ
for this group, link in my signature. Specifically see:

15.10 Why isn't "va_arg(argp, float)" working?

...at: http://www.eskimo.com/~scs/C-faq/q15.10.html

> 64 {
> 65 int res, i;
> 66 u8 data[32];
> 67 va_list args;
> 68
> 69 va_start(args, len);
> 70 for (i = 0; i < len; i++) {
> 71 data[i] = va_arg (args, u8);
> 72 }
> 73 va_end(args);
> 74 res = sn9c102_write_regs(cam, index, data, len);
> 75 if (res < 0) {
> 76 DEBUG(3, "Failed to write registers starting at index "
> 77 "0x%02X, error %d)", index, res)
> 78 return -1;
> 79 }
> 80 return 0;
> 81 }
>
> When I compile the code, I get the following message:
>
> sonix_pas202b.c: In function `sn9c102_write_va_regs':
> sonix_pas202b.c:74: warning: implicit declaration of function
> `sn9c102_write_regs'

Well, obviously you don't have a prototype for this function in scope.
Find the proper header and include it.

> sonix_pas202b.c:71: warning: `u8' is promoted to `int' when passed
> through `...'sonix_pas202b.c:71: warning: (so you should pass `int' not
> `u8' to `va_arg')
>
> Why does the warning on line 71 occur? I believe that 'u8'
> is typedef'ed somewhere in the linux kernel headers as an
> 'unsigned char', though I have not verified that yet. Is
> there a way of telling 'va_arg' the actual type of 'u8'?

No, there is no way at all to pass variable arguments to a variadic
function with a type less than int. They will be promoted to int by
the caller, assuming that it has a prototype for the variadic function
in scope. So you have to retrieve them as type int, then you can
assign them to your unsigned char array. There will be no change in
value.

> I'm compiling with GCC version 3.2.3 on Slackware Linux 9.1
> (kernel 2.4.22).
>
> Thanks,
>
> Mac Cody

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

Richard Bos

unread,
Jan 3, 2005, 10:31:52 AM1/3/05
to
jacob navia <ja...@jacob.remcomp.fr> wrote:

> Mac A. Cody wrote:

> > #include <stdarg.h>

> > 63 int sn9c102_write_va_regs(struct sn9c102_device* cam,
> > u16 index, int len, ...)
> > 64 {

> > 66 u8 data[32];
> > 67 va_list args;

> > 71 data[i] = va_arg (args, u8);

> > 74 res = sn9c102_write_regs(cam, index, data, len);

> > When I compile the code, I get the following message:


> >
> > sonix_pas202b.c: In function `sn9c102_write_va_regs':
> > sonix_pas202b.c:74: warning: implicit declaration of function
> > `sn9c102_write_regs'
> > sonix_pas202b.c:71: warning: `u8' is promoted to `int' when passed
> > through `...'sonix_pas202b.c:71: warning: (so you should pass `int' not
> > `u8' to `va_arg')

> Since the compiler didn't see the prototype of the function


> it will promote u8 to int, and warns you about it.

Bullshit. There _is_ a prototype. The lack of declaration of
sn9c102_write_regs (what a monster of a name, btw!) is completely beside
the point, for line 71. The problem is with the application of va_arg
and sn9c102_write_va_regs, for both of which a good declaration is in
scope.
The real problem is not a _lack_ of prototype, but the fact that the
prototype in question is a variadic one. This means that the arguments
in the variadic part are subject to the Usual Arithmetic Conversions as
much as when there had not been a prototype at all. There's nothing you
can do about that, either. There simply is no typing information in
"...", therefore the UACs kick in, and therefore there is no way a
variadic function can receive anything smaller than an int as one of its
variable arguments.

> Always prototype the functions before calling them, specially
> when writing an OS!

Always remember that prototyping doesn't protect you from the UACs if
you're using variadic functions.

Richard

Mac A. Cody

unread,
Jan 3, 2005, 6:02:52 PM1/3/05
to
Michael Mair wrote:
> Yes. Variable arguments of vararg functions get promoted, i.e. you
> cannot pass just a char but will always get an int. That is, you
> (necessarily) pass the u8 values as int values -- and have to retrieve
> them as such. The same happens to functions without prototypes.

Okay, I understand now. The webpage I found didn't mention the point
about the promtion of chars to ints.

> Something else: You should check against a buffer overrun of data
> in the loop l70 -- l72.
>

Good point. An overrun at that point would not be a nice thing.

> Cheers
> Michael

Thanks for responding!

Regards,

Mac

Mac A. Cody

unread,
Jan 3, 2005, 6:07:28 PM1/3/05
to
Richard Bos wrote:

> jacob navia <ja...@jacob.remcomp.fr> wrote:
>
>>Since the compiler didn't see the prototype of the function
>>it will promote u8 to int, and warns you about it.
>
>
> Bullshit. There _is_ a prototype. The lack of declaration of
> sn9c102_write_regs (what a monster of a name, btw!) is completely beside

That name wasn't my idea, though sn9c102_write_va_regs isn't much
better! :^/

> the point, for line 71. The problem is with the application of va_arg
> and sn9c102_write_va_regs, for both of which a good declaration is in
> scope.
> The real problem is not a _lack_ of prototype, but the fact that the
> prototype in question is a variadic one. This means that the arguments
> in the variadic part are subject to the Usual Arithmetic Conversions as
> much as when there had not been a prototype at all. There's nothing you
> can do about that, either. There simply is no typing information in
> "...", therefore the UACs kick in, and therefore there is no way a
> variadic function can receive anything smaller than an int as one of its
> variable arguments.
>

Thanks for the clarification!

>>Always prototype the functions before calling them, specially
>>when writing an OS!
>

Correct. I just have not placed the function in its final location,
where all of that will clear up.

> Always remember that prototyping doesn't protect you from the UACs if
> you're using variadic functions.
>
> Richard

Thanks again,

Mac

Mac A. Cody

unread,
Jan 3, 2005, 6:11:58 PM1/3/05
to
Jack Klein wrote:
> On Mon, 03 Jan 2005 00:58:05 -0600, "Mac A. Cody"
> <mac...@castcom.net> wrote in comp.lang.c:
>
>
>>Hello,
>>
>>I'm encountering a problem with using stdarg that I cannot
>>figure out. I'm trying to develop a function for a linux
>>driver module that takes a variable-length sequence of
>>u8-type values. Below is the function:
>>
>>#include <stdarg.h>
>>.
>>.
>>.
>>63 int sn9c102_write_va_regs(struct sn9c102_device* cam,
>> u16 index, int len, ...)
>
>
> You can't pass unsigned characters as part of the "..." arguments to
> variadic functions. You can't pass any of the character types, or
> signed or unsigned short, or floats. The arguments to such functions,
> after the fixed ones, undergo the default promotions.
>
> See section 15 on functions with variable argument lists in the FAQ
> for this group, link in my signature. Specifically see:
>
> 15.10 Why isn't "va_arg(argp, float)" working?
>
> ...at: http://www.eskimo.com/~scs/C-faq/q15.10.html
>

That reference was very helpful. Thanks!

>>64 {
>>65 int res, i;
>>66 u8 data[32];
>>67 va_list args;
>>68
>>69 va_start(args, len);
>>70 for (i = 0; i < len; i++) {
>>71 data[i] = va_arg (args, u8);
>>72 }
>>73 va_end(args);
>>74 res = sn9c102_write_regs(cam, index, data, len);
>>75 if (res < 0) {
>>76 DEBUG(3, "Failed to write registers starting at index "
>>77 "0x%02X, error %d)", index, res)
>>78 return -1;
>>79 }
>>80 return 0;
>>81 }
>>
>>When I compile the code, I get the following message:
>>
>>sonix_pas202b.c: In function `sn9c102_write_va_regs':
>>sonix_pas202b.c:74: warning: implicit declaration of function
>>`sn9c102_write_regs'
>
>
> Well, obviously you don't have a prototype for this function in scope.
> Find the proper header and include it.
>

Obviously true. I didn't think to mention it due to its
obviousness. In my haste, I failed to cut it out of my message.

>>sonix_pas202b.c:71: warning: `u8' is promoted to `int' when passed
>>through `...'sonix_pas202b.c:71: warning: (so you should pass `int' not
>>`u8' to `va_arg')
>>
>>Why does the warning on line 71 occur? I believe that 'u8'
>>is typedef'ed somewhere in the linux kernel headers as an
>>'unsigned char', though I have not verified that yet. Is
>>there a way of telling 'va_arg' the actual type of 'u8'?
>
>
> No, there is no way at all to pass variable arguments to a variadic
> function with a type less than int. They will be promoted to int by
> the caller, assuming that it has a prototype for the variadic function
> in scope. So you have to retrieve them as type int, then you can
> assign them to your unsigned char array. There will be no change in
> value.
>

Yes, I see that now. After twenty years of C programming (off and on),
this is the first time I've ever used the stdarg facility. Guess you
can never be too old to learn something about C!

Thanks,

Mac

Lawrence Kirby

unread,
Jan 4, 2005, 9:11:36 AM1/4/05
to
On Mon, 03 Jan 2005 15:31:52 +0000, Richard Bos wrote:

...

> The real problem is not a _lack_ of prototype, but the fact that the
> prototype in question is a variadic one. This means that the arguments
> in the variadic part are subject to the Usual Arithmetic Conversions as
> much as when there had not been a prototype at all.

Or rather the default argument promotions.

Lawrence

0 new messages