Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: memcpy not memcpying? Date: Mon, 04 Nov 2019 22:01:01 -0800 Organization: A noiseless patient Spider Lines: 84 Message-ID: <864kzig8v6.fsf@linuxsc.com> References: <2LVuF.7$BF1.0@fx26.iad> <6KfvF.57888$rJ1.57717@fx01.am4> <0DivF.23103$Q26.16540@fx34.am4> <1BAvF.13970$mB7.12243@fx32.am4> <%%DvF.115593$Yl3.480@fx24.am4> <87eeynlwc7.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="59b683b75f73ead2c1b20aa011ddc5ef"; logging-data="7168"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX190v3qmJNktL90rj3G4iY/wxWR1K2enDPA=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:lBOE4F24SibXICp7VhNYZqfxwkc= sha1:HCmMWU3tWNdUMy31VP3sqBGiwis= Xref: csiph.com comp.lang.c:147592 Ben Bacarisse writes: > David Brown writes: > > >> You plan your program. Is it realistic to think that the type of >> "nsymbols" would change - that 2 G symbols will not be enough? If that >> is the case, you write: >> >> typedef int symbolcount_t; >> symbolcount_t nsymbols; >> #define PRIsymbolcount d > > #define PRIsymbolcount "d" > >> void debug_print_symbolcounts(symbolcount__t i) { >> printf("Symbol %" PRIsymbolcount " out of %" PRIsymbolcount, >> i, nsymbols); >> } >> >> Or maybe, if you don't like printf format macros (and lets be honest, no >> one does - even if it is the least bad solution, it is still ugly), you >> write: >> >> typedef int symbolcount_t; >> symbolcount_t nsymbols; >> >> void print_symbolcounts(symbolcount_t i) { >> _Static_assert(sizeof(symbolcount_t) == sizeof(int), >> "Fix this function if symbolcount_t changes"); >> printf("%d", i); >> } > > I think I might use _Generic here because checking the size is not > always going to be enough: > > _Static_assert( > _Generic(i, int: 1, default: 0), > "Check this because symbolcount_t is not compatible with int." > ); > > This works (in both clang and gcc) with -std=c11 -pedantic, but I am not > sure that _Generic /must/ be allowed here. It would be a shame if > generic selections were not considered to be standard constant > expressions. Have I missed something in the standard? An implementation may accept it. However, an argument can be made that an implementation may rightfully reject this _Static_assert (and most _Static_assert declarations with a _Generic controlling expression) because it has undefined behavior. Undefined behavior arises because the controlling expression of a _Static_assert "shall [not in a Constraint] be an integer constant expression". Integer constant expressions are limited in what their operands can be: [They] "shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, _Alignof expressions, and floating constants that are the immediate operands of casts." The operand 'i' is not any of those. We might say the operand is not 'i' but the type of the expression 'i', but types too are not any of the things on the list. We might say the operand 'i' is not evaluated so it doesn't count, but not being evaluated looks like it doesn't matter for the ICE operand requirement. For example, _Static_assert( 0 ? i : 1, "OOPS" ); gives (with gcc) a diagnostic saying "expression in static assertion is not an integer constant expression". Don't get me wrong, I don't think this reading is what the authors intended. But I think the construction is reasonable based just on what text appears in the Standard. One other item. The condition used in the _Static_assert above is more restrictive than it needs to be. The printf() call will work if the type is 'int', but it will also work with 'signed char', or 'short', etc, because of integer promotions. The assertion can be fixed by changing the controlling expression of the _Generic() expression, thusly: _Generic( 0 ? 0 : i, int: 1, default: 0 ) which will convert any sub-int integer type to int, and leave others alone.