function calls, mandatory compiler promotion of int arguments tosize_t?

Discussion in 'C Programming' started by David Mathog, Aug 1, 2008.

  1. David Mathog

    David Mathog Guest

    For this small test program:

    #include <stdio.h>
    void main(void){
    char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    int size, count;
    size = 27; /* always a small number which will fit in an int */
    count = 1; /* ditto */
    (void) fwrite(buffer, size, count, stdout);
    }

    The int variables size and count are both used for fwrite() arguments
    which are prototyped to be size_t. If size_t is bigger than int (as on
    some 64 bit systems where size_t is 8 bytes and int is 4 bytes), does
    the C standard require the compiler to promote these two int values to
    size_t before passing them to the function, and if so, what exactly does
    it say?

    I know that in _practice_ the code above works, but I am curious if that
    must always be the case.

    Thanks,

    David Mathog
    David Mathog, Aug 1, 2008
    #1
    1. Advertising

  2. Re: function calls, mandatory compiler promotion of int arguments to size_t?

    Eric Sosman <> writes:
    [...]
    > Yes, it is. Note that the prototype-governed conversions cut both
    > ways, though: If you pass a "wide" argument expression to a prototyped
    > function with a "narrower" parameter, the conversion from wide to narrow
    > may lose information silently.


    Or it may give you some unexpected result. Conversion to a signed
    integer type, if the value can't be represented in the target type,
    yields an implementation-defined result (or raises an
    implementation-defined signal; the latter is new in C99).

    > Similarly, if you pass a floating-point
    > argument to a prototyped integer parameter, the fractional part vanishes
    > silently. (There's the seedling of an IOCCC entry here, I think: try
    > `malloc(atan(42.0))' to allocate an 88-byte object ...)


    For certain values of 42.0.

    Actually, for *no* values of 42.0; the results of atan() are in the
    range [-pi/2, +pi/2] (radians).

    But tan(1.5595) would do it. Note that very small changes in the
    argument result in large changes in the result.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 1, 2008
    #2
    1. Advertising

  3. Re: function calls, mandatory compiler promotion of int arguments to size_t?

    Eric Sosman <> writes:
    > Keith Thompson wrote:
    >> Eric Sosman <> writes:
    >> [...]
    >>> Yes, it is. Note that the prototype-governed conversions cut both
    >>> ways, though: If you pass a "wide" argument expression to a prototyped
    >>> function with a "narrower" parameter, the conversion from wide to narrow
    >>> may lose information silently.

    >> Or it may give you some unexpected result. Conversion to a signed
    >> integer type, if the value can't be represented in the target type,
    >> yields an implementation-defined result (or raises an
    >> implementation-defined signal; the latter is new in C99).

    >
    > Both of these qualify as "losing information," in my view.


    But raising a signal doesn't necesssarily qualify as "silently".

    [snip]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 1, 2008
    #3
  4. David Mathog

    David Mathog Guest

    Re: function calls, mandatory compiler promotion of int argumentsto size_t?

    Eric Sosman wrote:
    > David Mathog wrote:
    >> For this small test program:
    >>
    >> #include <stdio.h>
    >> void main(void){

    >
    > Tut. Tut, tut, tut. Consider your wrist slapped.


    Exit status and error checking were intentionally sacrificed for a
    shorter example program. I agree that real programs shouldn't do this,
    but by going with "void main" and throwing out the one status value
    returned the example program was able to drop a few lines which had
    nothing to do with the question at hand.

    >
    > Yes, and 6.5.2.2p7: "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."


    Perfect, that was exactly what I wanted to know.

    Thanks,

    David Mathog
    David Mathog, Aug 1, 2008
    #4
  5. Re: function calls, mandatory compiler promotion of int arguments to size_t?

    David Mathog <> writes:

    > Eric Sosman wrote:
    >> David Mathog wrote:
    >>> For this small test program:
    >>>
    >>> #include <stdio.h>
    >>> void main(void){

    >>
    >> Tut. Tut, tut, tut. Consider your wrist slapped.

    >
    > Exit status and error checking were intentionally sacrificed for a
    > shorter example program.


    In fact, C99 permits the return <exp>; to be omitted (zero is assumed)
    so int main(void)... is even shorter (OK, by only one character) /and/
    letter-of-the-law correct.

    --
    Ben.
    Ben Bacarisse, Aug 1, 2008
    #5
  6. Re: function calls, mandatory compiler promotion of int argumentsto size_t?

    On 1 Aug 2008 at 22:29, David Mathog wrote:
    > Eric Sosman wrote:
    >> David Mathog wrote:
    >>> void main(void){

    >>
    >> Tut. Tut, tut, tut. Consider your wrist slapped.

    >
    > Exit status and error checking were intentionally sacrificed for a
    > shorter example program. I agree that real programs shouldn't do this,
    > but by going with "void main" and throwing out the one status value
    > returned the example program was able to drop a few lines which had
    > nothing to do with the question at hand.


    Unfortunately that won't wash with many of the "regulars" around here.
    They don't know much about C, but they do have a religious zeal for
    getting the return type of main "correct".

    Many of them will try to argue that having void main there might have
    everything to do with the question at hand, since according to clc dogma
    it invokes UB, and they expect the compiler then to do everything in its
    power to make your program go wrong.

    The fact that this is complete nonsense in the real world means not a
    whit to them.
    Antoninus Twink, Aug 1, 2008
    #6
  7. David Mathog

    Guest

    On Aug 2, 1:29 am, David Mathog <> wrote:
    > Eric Sosman wrote:
    > > David Mathog wrote:
    > >> For this small test program:

    >
    > >> #include <stdio.h>
    > >> void main(void){

    >
    > > Tut. Tut, tut, tut. Consider your wrist slapped.

    >
    > Exit status and error checking were intentionally sacrificed for a
    > shorter example program.


    Then why the superfluous cast in the fwrite call?
    , Aug 2, 2008
    #7
  8. David Mathog

    Guest

    On Aug 1, 10:48 pm, David Mathog <> wrote:
    > For this small test program:
    >
    > #include <stdio.h>
    > void main(void){
    > char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    > int size, count;
    > size = 27; /* always a small number which will fit in an int */
    > count = 1; /* ditto */
    > (void) fwrite(buffer, size, count, stdout);
    >
    > }
    >
    > The int variables size and count are both used for fwrite() arguments
    > which are prototyped to be size_t. If size_t is bigger than int (as on
    > some 64 bit systems where size_t is 8 bytes and int is 4 bytes), does
    > the C standard require the compiler to promote these two int values to
    > size_t before passing them to the function, and if so, what exactly does
    > it say?


    You got good replies for these questions. Something I wanted to add is
    that you got the order of size/nmemb arguments in the fwrite call
    wrong; it's even harder to see that because of the misleading variable
    names.
    It should be
    1 27
    fwrite(buffer, count, size, stdout);

    > I know that in _practice_ the code above works, but I am curious if that
    > must always be the case.


    It doesn't, it's not.
    , Aug 2, 2008
    #8
  9. David Mathog

    santosh Guest

    Re: function calls, mandatory compiler promotion of int arguments to size_t?

    wrote:

    > On Aug 1, 10:48 pm, David Mathog <> wrote:
    >> For this small test program:
    >>
    >> #include <stdio.h>
    >> void main(void){
    >> char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    >> int size, count;
    >> size = 27; /* always a small number which will fit in an int */
    >> count = 1; /* ditto */
    >> (void) fwrite(buffer, size, count, stdout);
    >>
    >> }


    [ ... ]

    > You got good replies for these questions. Something I wanted to add is
    > that you got the order of size/nmemb arguments in the fwrite call
    > wrong; it's even harder to see that because of the misleading variable
    > names.
    > It should be
    > 1 27
    > fwrite(buffer, count, size, stdout);
    >
    >> I know that in _practice_ the code above works, but I am curious if
    >> that must always be the case.

    >
    > It doesn't, it's not.


    Does it _really_ fail if 'size' and 'count' are switched in this case?
    Does the Standard say a call that interchanges these two arguments
    _must_ be wrong? Beyond the difference in the return value, and it's
    implications upon a partial write, which was recently discussed, what
    difference would it actually make for fwrite itself whether it views
    it's data as one element of N bytes or as N elements of one byte?
    santosh, Aug 2, 2008
    #9
  10. David Mathog

    Ike Naar Guest

    In article <>,
    <> wrote:
    >On Aug 1, 10:48 pm, David Mathog <> wrote:
    >> #include <stdio.h>
    >> void main(void){
    >> char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    >> int size, count;
    >> size = 27; /* always a small number which will fit in an int */
    >> count = 1; /* ditto */
    >> (void) fwrite(buffer, size, count, stdout);
    >>
    >> }
    >>

    >You got good replies for these questions. Something I wanted to add is
    >that you got the order of size/nmemb arguments in the fwrite call
    >wrong; it's even harder to see that because of the misleading variable
    >names.
    >It should be
    > 1 27
    > fwrite(buffer, count, size, stdout);


    David Mathog's code writes one 27-byte chunk.
    Yours writes 27 1-byte chunks.
    Neither version is "wrong" per se.
    Ike Naar, Aug 2, 2008
    #10
  11. David Mathog

    Guest

    On Aug 2, 2:21 pm, santosh <> wrote:
    > wrote:
    > > On Aug 1, 10:48 pm, David Mathog <> wrote:
    > >> For this small test program:

    >
    > >> #include <stdio.h>
    > >> void main(void){
    > >> char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    > >> int size, count;
    > >> size = 27; /* always a small number which will fit in an int */
    > >> count = 1; /* ditto */
    > >> (void) fwrite(buffer, size, count, stdout);

    >
    > >> }

    >
    > [ ... ]
    >
    > > You got good replies for these questions. Something I wanted to add is
    > > that you got the order of size/nmemb arguments in the fwrite call
    > > wrong; it's even harder to see that because of the misleading variable
    > > names.
    > > It should be
    > > 1 27
    > > fwrite(buffer, count, size, stdout);

    >
    > >> I know that in _practice_ the code above works, but I am curious if
    > >> that must always be the case.

    >
    > > It doesn't, it's not.

    >
    > Does it _really_ fail if 'size' and 'count' are switched in this case?
    > Does the Standard say a call that interchanges these two arguments
    > _must_ be wrong? Beyond the difference in the return value, and it's
    > implications upon a partial write, which was recently discussed, what
    > difference would it actually make for fwrite itself whether it views
    > it's data as one element of N bytes or as N elements of one byte?



    They are both correct. However I was refering to 'void main()'.
    (assuming hosted implementation)
    , Aug 2, 2008
    #11
  12. Re: function calls, mandatory compiler promotion of int arguments to size_t?

    On Fri, 01 Aug 2008 12:48:21 -0700, David Mathog <>
    wrote:

    >For this small test program:
    >
    >#include <stdio.h>
    >void main(void){
    >char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    >int size, count;
    > size = 27; /* always a small number which will fit in an int */
    > count = 1; /* ditto */
    > (void) fwrite(buffer, size, count, stdout);
    >}
    >
    >The int variables size and count are both used for fwrite() arguments
    >which are prototyped to be size_t. If size_t is bigger than int (as on
    >some 64 bit systems where size_t is 8 bytes and int is 4 bytes), does
    >the C standard require the compiler to promote these two int values to
    >size_t before passing them to the function, and if so, what exactly does
    >it say?


    As long as others have picked the nits, this is not a promotion in the
    way the standard uses the term. It is a conversion as if by
    assignment. If you change size and count to long and have a system
    where size_t is unsigned int, the compiler is still required to
    convert the arguments to the type expected by the called function
    (even though it is a demotion).

    --
    Remove del for email
    Barry Schwarz, Aug 2, 2008
    #12
  13. David Mathog

    santosh Guest

    Re: function calls, mandatory compiler promotion of int arguments to size_t?

    wrote:

    > On Aug 2, 2:21 pm, santosh <> wrote:
    >> wrote:
    >> > On Aug 1, 10:48 pm, David Mathog <> wrote:
    >> >> For this small test program:

    >>
    >> >> #include <stdio.h>
    >> >> void main(void){
    >> >> char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    >> >> int size, count;
    >> >> size = 27; /* always a small number which will fit in an int
    >> >> */
    >> >> count = 1; /* ditto
    >> >> */ (void) fwrite(buffer, size, count, stdout);

    >>
    >> >> }

    >>
    >> [ ... ]


    >> >> I know that in _practice_ the code above works, but I am curious
    >> >> if that must always be the case.

    >>
    >> > It doesn't, it's not.

    >>
    >> Does it _really_ fail if 'size' and 'count' are switched in this
    >> case? [ ... ]


    > They are both correct. However I was refering to 'void main()'.
    > (assuming hosted implementation)


    Ah, OK. I failed to notice that error.
    santosh, Aug 2, 2008
    #13
  14. Re: function calls, mandatory compiler promotion of int arguments to size_t?

    On Sat, 2 Aug 2008 03:12:57 -0700 (PDT),
    <> wrote:
    > On Aug 1, 10:48 pm, David Mathog <> wrote:
    >> For this small test program:
    >>
    >> #include <stdio.h>
    >> void main(void){
    >> char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    >> int size, count;
    >> size = 27; /* always a small number which will fit in an int */
    >> count = 1; /* ditto */
    >> (void) fwrite(buffer, size, count, stdout);
    >>
    >> }
    >>
    >> The int variables size and count are both used for fwrite() arguments
    >> which are prototyped to be size_t. If size_t is bigger than int (as on
    >> some 64 bit systems where size_t is 8 bytes and int is 4 bytes), does
    >> the C standard require the compiler to promote these two int values to
    >> size_t before passing them to the function, and if so, what exactly does
    >> it say?

    >
    > You got good replies for these questions. Something I wanted to add is
    > that you got the order of size/nmemb arguments in the fwrite call
    > wrong; it's even harder to see that because of the misleading variable
    > names.
    > It should be
    > 1 27
    > fwrite(buffer, count, size, stdout);


    How did you conclude that David meant to write 27 elements of 1 byte
    each, rather than 1 element of 27 bytes? Or are you saying that it is
    not possible to have an element of 27 bytes?

    And what do you mean by 'misleading variable names'? The prototype for
    fwrite is:

    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

    (C99 adds some restricts in there as well),

    So David's variable names match that quite well: 'size' for 'size' and
    'count' for 'nmemb'. How is that misleading? Or is this simply a result
    of your assumption that David swapped them around?

    Martien
    --
    |
    Martien Verbruggen | life ain't fair, but the root password helps.
    | -- BOFH
    |
    Martien Verbruggen, Aug 3, 2008
    #14
  15. David Mathog

    CBFalconer Guest

    blargg wrote:
    > Antoninus Twink <> wrote:
    >

    .... snip ...
    >
    > Sometimes UB like this is relevant to the person's question/problem
    >, so ignoring it might be ignoring the problem. Besides, it's an
    > easy fix and why not use the context as an opportunity to educate?
    >
    >> The fact that this is complete nonsense in the real world means
    >> not a whit to them.

    >
    > Either one is posting a compilable, runnable example, or one is
    > not. If not, why bother with #include <stdio.h>, or a main
    > function at all?


    Ignoring the fact that Twink is a troll, if not posting a complete
    compilable and runnable program, why bother posting at all? Think
    of the electrons that could be saved. You will save time and be
    able to contribute to PETE.

    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.
    CBFalconer, Aug 3, 2008
    #15
  16. David Mathog

    Guest

    On Aug 3, 3:23 am, (blargg) wrote:
    > In article <>, Antoninus Twink
    >
    >
    >
    > <> wrote:
    > > On 1 Aug 2008 at 22:29, David Mathog wrote:
    > > > Eric Sosman wrote:
    > > >> David Mathog wrote:
    > > >>> void main(void){

    >
    > > >> Tut. Tut, tut, tut. Consider your wrist slapped.

    >
    > > > Exit status and error checking were intentionally sacrificed for a
    > > > shorter example program. I agree that real programs shouldn't do this,
    > > > but by going with "void main" and throwing out the one status value
    > > > returned the example program was able to drop a few lines which had
    > > > nothing to do with the question at hand.

    >
    > > Unfortunately that won't wash with many of the "regulars" around here.
    > > They don't know much about C, but they do have a religious zeal for
    > > getting the return type of main "correct".

    >
    > > Many of them will try to argue that having void main there might have
    > > everything to do with the question at hand, since according to clc dogma
    > > it invokes UB, and they expect the compiler then to do everything in its
    > > power to make your program go wrong.

    >
    > Sometimes UB like this is relevant to the person's question/problem, so
    > ignoring it might be ignoring the problem. Besides, it's an easy fix and
    > why not use the context as an opportunity to educate?
    >
    > > The fact that this is complete nonsense in the real world means not a
    > > whit to them.

    >
    > Either one is posting a compilable, runnable example, or one is not. If
    > not, why bother with #include <stdio.h>, or a main function at all?


    It *is* compilable and runnable, but perhaps not with all compilers.
    AFAIK, the standard states that an implementation may accept an
    implementation-defined prototype for main(). I'd expect 'void
    main(void)' to be a common choice for such prototype, seems it looks
    fairly natural and is the one used in other languages.

    Sebastian
    , Aug 4, 2008
    #16
  17. David Mathog

    santosh Guest

    Re: function calls, mandatory compiler promotion of int arguments to size_t?

    wrote:

    <snip>

    > AFAIK, the standard states that an implementation may accept an
    > implementation-defined prototype for main(). I'd expect 'void
    > main(void)' to be a common choice for such prototype, seems it looks
    > fairly natural and is the one used in other languages.


    I would always return a sensible value back to the system. Returning
    garbage values (which is what happens when you use void main) breaks
    scripts and wrapper programs. Just return 0 or EXIT_FAILURE. Why is
    this so hard?
    santosh, Aug 4, 2008
    #17
  18. David Mathog

    Richard Bos Guest

    Re: function calls, mandatory compiler promotion of int arguments to size_t?

    wrote:

    > On Aug 3, 3:23 am, (blargg) wrote:


    > > Either one is posting a compilable, runnable example, or one is not. If
    > > not, why bother with #include <stdio.h>, or a main function at all?

    >
    > It *is* compilable and runnable, but perhaps not with all compilers.


    So is

    int WINAPI WinMain(HINSTANCE instance, HINSTANCE previnst__,
    PSTR cmdline, int showmode)

    but you wouldn't recommend that as a sensible form of the main program
    to be posted to this newsgroup, would you?

    Richard
    Richard Bos, Aug 4, 2008
    #18
  19. David Mathog

    David Mathog Guest

    Re: function calls, mandatory compiler promotion of int argumentsto size_t?

    wrote:
    > On Aug 2, 1:29 am, David Mathog <> wrote:
    >> Eric Sosman wrote:
    >>> David Mathog wrote:
    >>>> For this small test program:
    >>>> #include <stdio.h>
    >>>> void main(void){
    >>> Tut. Tut, tut, tut. Consider your wrist slapped.

    >> Exit status and error checking were intentionally sacrificed for a
    >> shorter example program.

    >
    > Then why the superfluous cast in the fwrite call?


    (void) fwrite(buffer, size, count, stdout);

    Tells the compiler (and anybody reading the program) that the return
    value is intentionally being ignored. Leave that off and in their
    pickier modes many compilers will issue a warning about the unused
    return value.

    Regards,

    David Mathog
    David Mathog, Aug 4, 2008
    #19
  20. David Mathog

    David Mathog Guest

    Re: function calls, mandatory compiler promotion of int argumentsto size_t?

    wrote:
    > On Aug 1, 10:48 pm, David Mathog <> wrote:
    >> For this small test program:
    >>
    >> #include <stdio.h>
    >> void main(void){
    >> char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
    >> int size, count;
    >> size = 27; /* always a small number which will fit in an int */
    >> count = 1; /* ditto */
    >> (void) fwrite(buffer, size, count, stdout);


    > You got good replies for these questions. Something I wanted to add is
    > that you got the order of size/nmemb arguments in the fwrite call
    > wrong; it's even harder to see that because of the misleading variable
    > names.
    > It should be
    > 1 27
    > fwrite(buffer, count, size, stdout);


    I know what you're saying, but in this instance I really did intend that
    it be one big write. The example program was derived from a real one
    where a large buffer had to be written entirely. Simplified a bit, the
    original code was like this:

    size=262144;
    if(!fwrite(buffer,size,1,stdout)failure_function("message");

    What you are saying is correct and useful if there is something to be
    gained by knowing that 123456 out of 2626144 characters were written
    before the output failed. In this instance a failure is a failure and
    that extra information is not needed.

    Regards,

    David Mathog
    David Mathog, Aug 4, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Timothy Madden
    Replies:
    4
    Views:
    372
    Timothy Madden
    Sep 28, 2004
  2. Schnoffos
    Replies:
    2
    Views:
    1,206
    Martien Verbruggen
    Jun 27, 2003
  3. Hal Styli
    Replies:
    14
    Views:
    1,626
    Old Wolf
    Jan 20, 2004
  4. Tomás Ó hÉilidhe

    Compiler-extension small int type promotion

    Tomás Ó hÉilidhe, Dec 20, 2008, in forum: C Programming
    Replies:
    15
    Views:
    662
    Tomás Ó hÉilidhe
    Dec 22, 2008
  5. Bob
    Replies:
    5
    Views:
    259
Loading...

Share This Page