Confusion with stdarg

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mac A. Cody

    #1

    Confusion with stdarg

    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_v a_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_r egs(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_pas2 02b.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

    #2
    Re: Confusion with stdarg

    Mac A. Cody wrote:[color=blue]
    > 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_v a_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_r egs(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_pas2 02b.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
    >[/color]
    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!

    Comment

    • Mac A. Cody

      #3
      Re: Confusion with stdarg

      jacob navia wrote:[color=blue]
      > Mac A. Cody wrote:
      >[color=green]
      >> 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_v a_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_r egs(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_pas2 02b.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
      >>[/color]
      > 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!
      >[/color]

      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

      Comment

      • Michael Mair

        #4
        Re: Confusion with stdarg



        Mac A. Cody wrote:[color=blue]
        > jacob navia wrote:
        >[color=green]
        >> Mac A. Cody wrote:
        >>[color=darkred]
        >>> 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_v a_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_r egs(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_pas2 02b.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
        >>>[/color]
        >> 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!
        >>[/color]
        >
        > 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.
        >[/color]

        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.

        Comment

        • Jack Klein

          #5
          Re: Confusion with stdarg

          On Mon, 03 Jan 2005 00:58:05 -0600, "Mac A. Cody"
          <maccody@castco m.net> wrote in comp.lang.c:
          [color=blue]
          > 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_v a_regs(struct sn9c102_device* cam,
          > u16 index, int len, ...)[/color]

          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(arg p, float)" working?

          ....at: http://www.eskimo.com/~scs/C-faq/q15.10.html
          [color=blue]
          > 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_r egs(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'[/color]

          Well, obviously you don't have a prototype for this function in scope.
          Find the proper header and include it.
          [color=blue]
          > sonix_pas202b.c :71: warning: `u8' is promoted to `int' when passed
          > through `...'sonix_pas2 02b.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'?[/color]

          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.
          [color=blue]
          > I'm compiling with GCC version 3.2.3 on Slackware Linux 9.1
          > (kernel 2.4.22).
          >
          > Thanks,
          >
          > Mac Cody[/color]

          --
          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.l earn.c-c++

          Comment

          • Richard Bos

            #6
            Re: Confusion with stdarg

            jacob navia <jacob@jacob.re mcomp.fr> wrote:
            [color=blue]
            > Mac A. Cody wrote:[/color]
            [color=blue][color=green]
            > > #include <stdarg.h>[/color][/color]
            [color=blue][color=green]
            > > 63 int sn9c102_write_v a_regs(struct sn9c102_device* cam,
            > > u16 index, int len, ...)
            > > 64 {[/color][/color]
            [color=blue][color=green]
            > > 66 u8 data[32];
            > > 67 va_list args;[/color][/color]
            [color=blue][color=green]
            > > 71 data[i] = va_arg (args, u8);[/color][/color]
            [color=blue][color=green]
            > > 74 res = sn9c102_write_r egs(cam, index, data, len);[/color][/color]
            [color=blue][color=green]
            > > 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_pas2 02b.c:71: warning: (so you should pass `int' not
            > > `u8' to `va_arg')[/color][/color]
            [color=blue]
            > Since the compiler didn't see the prototype of the function
            > it will promote u8 to int, and warns you about it.[/color]

            Bullshit. There _is_ a prototype. The lack of declaration of
            sn9c102_write_r egs (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_v a_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.
            [color=blue]
            > Always prototype the functions before calling them, specially
            > when writing an OS![/color]

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

            Richard

            Comment

            • Mac A. Cody

              #7
              Re: Confusion with stdarg

              Michael Mair wrote:[color=blue]
              > 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.[/color]

              Okay, I understand now. The webpage I found didn't mention the point
              about the promtion of chars to ints.
              [color=blue]
              > Something else: You should check against a buffer overrun of data
              > in the loop l70 -- l72.
              >[/color]
              Good point. An overrun at that point would not be a nice thing.
              [color=blue]
              > Cheers
              > Michael[/color]

              Thanks for responding!

              Regards,

              Mac

              Comment

              • Mac A. Cody

                #8
                Re: Confusion with stdarg

                Richard Bos wrote:[color=blue]
                > jacob navia <jacob@jacob.re mcomp.fr> wrote:
                >[color=green]
                >>Since the compiler didn't see the prototype of the function
                >>it will promote u8 to int, and warns you about it.[/color]
                >
                >
                > Bullshit. There _is_ a prototype. The lack of declaration of
                > sn9c102_write_r egs (what a monster of a name, btw!) is completely beside[/color]

                That name wasn't my idea, though sn9c102_write_v a_regs isn't much
                better! :^/
                [color=blue]
                > the point, for line 71. The problem is with the application of va_arg
                > and sn9c102_write_v a_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.
                >[/color]

                Thanks for the clarification!
                [color=blue][color=green]
                >>Always prototype the functions before calling them, specially
                >>when writing an OS![/color]
                >[/color]

                Correct. I just have not placed the function in its final location,
                where all of that will clear up.
                [color=blue]
                > Always remember that prototyping doesn't protect you from the UACs if
                > you're using variadic functions.
                >
                > Richard[/color]

                Thanks again,

                Mac

                Comment

                • Mac A. Cody

                  #9
                  Re: Confusion with stdarg

                  Jack Klein wrote:[color=blue]
                  > On Mon, 03 Jan 2005 00:58:05 -0600, "Mac A. Cody"
                  > <maccody@castco m.net> wrote in comp.lang.c:
                  >
                  >[color=green]
                  >>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_v a_regs(struct sn9c102_device* cam,
                  >> u16 index, int len, ...)[/color]
                  >
                  >
                  > 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(arg p, float)" working?
                  >
                  > ...at: http://www.eskimo.com/~scs/C-faq/q15.10.html
                  >[/color]

                  That reference was very helpful. Thanks!
                  [color=blue][color=green]
                  >>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_r egs(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_writ e_regs'[/color]
                  >
                  >
                  > Well, obviously you don't have a prototype for this function in scope.
                  > Find the proper header and include it.
                  >[/color]

                  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.
                  [color=blue][color=green]
                  >>sonix_pas202b .c:71: warning: `u8' is promoted to `int' when passed
                  >>through `...'sonix_pas2 02b.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'?[/color]
                  >
                  >
                  > 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.
                  >[/color]

                  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

                  Comment

                  • Lawrence Kirby

                    #10
                    Re: Confusion with stdarg

                    On Mon, 03 Jan 2005 15:31:52 +0000, Richard Bos wrote:

                    ....
                    [color=blue]
                    > 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.[/color]

                    Or rather the default argument promotions.

                    Lawrence

                    Comment

                    Working...