Path: csiph.com!weretis.net!feeder8.news.weretis.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: Effect of CPP tags Date: Fri, 05 Jan 2024 18:17:40 -0800 Organization: None to speak of Lines: 83 Message-ID: <87o7dzryrf.fsf@nosuchdomain.example.com> References: <%cFlN.140487$xHn7.115393@fx14.iad> <87cyufxu1s.fsf@bsb.me.uk> MIME-Version: 1.0 Content-Type: text/plain Injection-Info: dont-email.me; posting-host="dd6f382ccf7ae1061731f5cc993e4880"; logging-data="384389"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18mW6UF0D5sc9gGPQ1qMHX/" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:k2V/kFvRkzlv8hqnhTOS8eKDui0= sha1:S2PGuLDdjOQU8iyGOGKh4Pg4TOo= Xref: csiph.com comp.lang.c:379874 Bart writes: > On 05/01/2024 23:02, Ben Bacarisse wrote: >> Bart writes: >>> In C, sizeof() is usually compile-time, except when used on VLAs, > and here, >>> as usual for VLAs, it is a lot more complicated than you'd think: >>> >>> -------- >>> #include >>> #include >>> >>> int main(void) { >>> int n=rand()+1; >>> typedef char (**T)[n]; >>> n=-777; >>> >>> T x; >>> >>> printf("%zu\n", sizeof(**x)); >>> } >>> -------- >>> >>> This actually displays 42 (really!). 'x' is a pointer (to a pointer to >>> array). There is no actual array allocated. >> >> More to the point, x is uninitialised and thus evaluating sizeof **x is >> undefined behaviour. gcc has some flags that could have helped you to >> find that out. > > I actually don't know if it's evaluating it or not. Why on earth > should it? If I change the program to print the original 'n', it is 42 > too. So it doesn't need to evaluate **x to get that dimension. The C standard currently says: The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant. The idea that the operand is "evaluated" is problematic. For example, if the argument is a parenthesized type name, it's not clear what it means to "evaluate" it. And there are cases (mostly contrived) where the rule results in side effects that aren't actually necessary to determine the size. If I write: int n = rand() % 10 + 1; int vla[n]; printf("%zu\n", sizeof vla); then the standard says that the expression `vla` is "evaluated". Since it's of array type, that would logically involve retrieving the values of each of its elements (there's no array-to-pointer conversion in this context), which would have undefined behavior because they're uninitialized. It's fairly clear that wasn't the intent; the only thing that needs to be evaluated is the implicit metadata that gives the size of the array. Jens Gustedt has written a proposal to address this, probably in C26. See . In practice, applying sizeof to a VLA type, or to a named object of VLA type, doesn't create any conceptual problems, and those are by far the most common cases. When a variable length array type is created, its length is determined when execution reaches the definition, and the compiler generates code to implicitly store that information somewhere for later use. If the length expression happens to be the name of an object, any later changes to the value of the object do not affect the VLA type or its size or length; I suggest you stop being surprised by that fact. Applying sizeof to a VLA type or object retrieves the stored size. [...] -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Medtronic void Void(void) { Void(); } /* The recursive call of the void */