Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: #include Date: Sun, 11 Jul 2021 15:30:13 -0700 Organization: None to speak of Lines: 99 Message-ID: <87mtqs5vre.fsf@nosuchdomain.example.com> References: <87wnqxxoe3.fsf@nosuchdomain.example.com> <86bl7vb24m.fsf@linuxsc.com> <874kdnw20s.fsf@nosuchdomain.example.com> <86sg0l6uza.fsf@linuxsc.com> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: reader02.eternal-september.org; posting-host="d99a2aa5e30c72b9011dead7e6361f9f"; logging-data="13339"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/RTK78JeMZ1A8k5chXVvTx" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:691SxFHd3bF3bE7Z22IzfY4EMVU= sha1:pvOB+Du9CcFAWwcYYI8fbY1D4TE= Xref: csiph.com comp.lang.c:161879 Tim Rentsch writes: > Keith Thompson writes: >> Tim Rentsch writes: >>> Keith Thompson writes: >>> [... on printing various integer types ...] >>> >>>> Using the macros: >>>> >>>> #include >>>> // #include >>>> #include >>>> #include >>>> >>>> int main(void) { >>>> printf("INT_MAX : %d\n", INT_MAX); >>>> printf("INT_MIN : %d\n", INT_MIN); >>>> printf("LONG_MAX : %ld\n", LONG_MAX); >>>> printf("LONG_MIN : %ld\n", LONG_MIN); >>>> printf("UINT_MAX : %u\n", UINT_MAX); >>>> printf("ULONG_MAX : %lu\n", ULONG_MAX); >>>> printf("USHRT_MAX : %u\n", (unsigned)USHRT_MAX); >>> >>> The cast in the last line is not needed. >>> >>>> printf("\nFrom stdint.h: \n"); >>>> printf("INT8_MAX : %" PRId8 "\n", INT8_MAX); >>>> printf("INT16_MAX : %" PRId16 "\n", INT16_MAX); >>>> printf("INT32_MAX : %" PRId32 "\n", INT32_MAX); >>>> printf("INT64_MAX : %" PRId64 "\n", INT64_MAX); >>>> printf("UINT8_MAX : %" PRIu8 "\n", UINT16_MAX); >>>> printf("UINT16_MAX : %" PRIu16 "\n", UINT16_MAX); >>>> printf("UINT32_MAX : %" PRIu32 "\n", UINT32_MAX); >>>> printf("UINT64_MAX : %" PRIu64 "\n", UINT64_MAX); >>>> } >>>> >>>> Most of the casts in your original program are unnecessary, since >>>> the expressions are already of the type you were casting them to. >>>> But unsigned short could promote either to signed int or to >>>> unsigned int, depending on their ranges, so converting to unsigned >>>> and using "%u" is appropriate. In general, when passed to a >>>> variadic function like printf, an argument of an integer type >>>> narrower than int is promoted to int if type's range fits in int, >>>> to unsigned int otherwise. >>> >>> The description of how type promotion works is right, however a >>> cast is still not needed there. The reason is that values given >>> as variadic arguments are allowed to be the corresponding signed >>> or unsigned version of the type used to get the value, and that >>> will work as long as the value is in the set of values common to >>> both types. If an unsigned short promotes to int, then its value >>> is guaranteed to be in the set of values representable by both >>> int and unsigned int, and hence using %u for an uncasted unsigned >>> short is always safe. >> >> My reading of the standard is that that's certainly the intent, but >> it's not quite stated explicitly. >> >> N1570 6.5.2.2 makes a similar guarantee for calls to a function defined >> without a prototype. >> >> 7.16.1.1 makes the same guarantee for arguments to the va_arg macro, >> which makes it clear that printf("%u\n", 1) is *supposed* to work, but I >> don't see a guarantee that the call itself (which happens before va_arg >> is invoked -- assuming printf even uses va_arg) has defined behavior. >> >> Or I'm missing something. > > I wrote a long reply to Ben Bacarisse in this same thread, you > may want to read that reply in addition to what I write here. > > Basically the question boils down to what is meant by the > somewhat vague phrase "the correct type". I believe that phrase > is meant to refer to the rules of 7.16.1.1. If you want to say > there's an ambiguity about what is meant, certainly I could agree > with that. For purposes of posting in comp.lang.c, my usual rule > is to judge the language according to what meaning is intended, > and since here we are in agreement about what is intended here we > are not in conflict. Whether the C standard "actually says" that > the va_arg rules apply to *printf functions is, I think, not > an answerable question, and in any case not really a useful > question for purposes of comp.lang.c. I am glad we agree about > what rule is intended, and IMO that is really all that matters > for the present discussion. I mostly agree, but I disagree with your statement about the va_arg rules applying to *printf. The standard doesn't say that the *printf functions use va_arg. The question of whether the standard *actually says* that va_arg rules apply to *printf functions is, I think, answerable, and the answer is no. Whether that matters is another question, but surely a question about whether the standard says something can be resolved by reading the standard. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips void Void(void) { Void(); } /* The recursive call of the void */