Path: csiph.com!news.mixmin.net!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: How to avoid an overflow during multiplication? Date: Fri, 04 Feb 2022 21:14:59 -0800 Organization: A noiseless patient Spider Lines: 146 Message-ID: <86ee4hlwrw.fsf@linuxsc.com> References: <8735m954yz.fsf@bsb.me.uk> <877dbk36qu.fsf@nosuchdomain.example.com> <86v8ydp57h.fsf@linuxsc.com> <86pmojo7th.fsf@linuxsc.com> <86sfszlsfd.fsf@linuxsc.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="fd296145b453fec571e4c44d6840aea3"; logging-data="12237"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+uL1J7tWiz0NP1X18IpcW/6+duUKlZws0=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:7aCyQNTy+7CovgOO+lT4EU96J00= sha1:Gsapd11d92iWrvX1bIsex+5IQKU= Xref: csiph.com comp.lang.c:164788 Mateusz Viste writes: > 2022-02-03 at 10:24 -0800, Tim Rentsch wrote: [...] >> If you don't give C99 an earnest try of non-trivial duration, >> you'll never know. > > [...] I do use C99 from time to time on some oddball projects, but > for my daily stuff I simply don't feel it brings anything on top of > what I have already with gnu89. But maybe I missed some key things, > so let me ask: what C99 feature do you use, that you wouldn't want > to loose? I see this as two or three related questions, which I will try to answer in turn. The third of these relates to the question of using option -std=gnuXX versus option -std=cXX, and is addressed in the last section. First there are several constructs that C89/C90 permits but are disallowed in C99: * calls to functions not previously declared are implicitly declared (with nothing known about the parameter types, and as returning type 'int') * declarations (especially functions) are allowed not to give a type specifier, in which case the type defaults to 'int' * 'return' statements need not give an expression in a function that returns a non-void type, and conversely I understand why K&R C (and later C89/C90) allowed these things. But they are all dangerous, especially implicit declaration of functions, and it is good that C99 requires them to be flagged. Second, there are lots of C99 additions (my list has at least 20) that I find useful. These span a range of utility but in each case either they offer something that is at best very inconvenient to do in C89/C90 or that is only a minor convenience but one I have gotten used to and would not want to give up. Here is a selected subset, in rough order of increasing significance: Number 10: 'enum' definitions allow a trailing comma. Only a convenience feature, but a useful one, and it makes the language more regular by aligning with the analogous rule for array initializers. Number 9: array parameters may have 'static' and 'const' etc. Normally I use array notation (eg, 'int x[]') for parameters that are treated as arrays rather than as pointers to single objects. This feature allows length and qualifier information to be added to the pointer parameter while still retaining array notation in the parameter declaration. Number 8: 'va_copy' macro. I found 'va_copy' indispensable while implementing an extension to printf(). Number 7: 'long long' type (and library functions). It's nice to have an integer type that is guaranteed to be at least 64 bits, which C89/C90 doesn't have. Number 6: snprintf and friends. Needed for safe formatting. Number 5: restricted pointers. Especially when a function has parameters that are pointers to characters, 'restrict' can help a lot with quality of generated code (because of aliasing concerns). Number 4: variadic macros. Compare this fragment case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: with this fragment cases(1,2,3,4,5,6,7,8,9): Variadic macros make writing a 'cases()' macro possible (and of course there are other applications as well). I /write/ variadic macros not very often, but I often see situations where /applying/ a variadic macro can make the code cleaner and neater. Number 3: variably modified types. Variable length arrays are sometimes problematic because of the danger of stack overflow. But variably modified types, which are akin to VLAs but not the same, provide similar benefits without the associated risk of blowing the stack. Number 2: non-constant block-level initializers for structs and arrays. In C89/C90 initializers for structs and array must have constant values for each element, including variables that are function locals. In C99 this limitation is removed, avoiding the need to do element-by-element assignment for what is logically just an initialization. Number 1: compound literals and designated initializers. I put these two features together because they are often used together and because there is some synergy between them. Individually, a compound literal is often a safer alternative to casting, and designated initializers provide an easy way of initializing a sparse array (provided "sparse" means most of the elements are zero). There are of course other applications but the last sentence gives a couple of common examples. I find myself using most of the features in the above list (not all certainly, but more than half) in almost every C program I work on. Third area: on the matter of -std=gnuXX versus -std=cXX. Many years ago I didn't pay much attention to differences between gnu C and ISO standard C. Little by little I became aware of the distinction and what some implications are of using one versus using the other. One key difference is that when using standard C you know what you're getting. To say that another way, standard C can be counted on to be the same across different platforms. Conversely it is frustrating to take a program that compiles under gnu C on one platform but doesn't on a different platform. I have seen this result a lot more often than I would like. A second key difference is that what "gnu C" means can (and unfortunately sometimes does) change over time. Standard C doesn't have that property (assuming of course we are sticking to one version of the ISO C standard, such as C99). I understand that some programs need access to functionality that simply is not available if compiling as strictly standard C. In such cases the use of non-standard options cannot be avoided, but it can be localized. If and when problems come up, they will be easier to deal with by virtue of being confined to a relatively small and well-defined part of the program. In times past I had a more laissez faire attitude toward allowing non-standard compiler options. What changed my mind was being bitten when something would work in one place or time and then not work in another place or time. Using strictly standard C is reliable and dependable, and that is worth a lot. Sometimes it is necessary to make a (local) pragmatic exception to that rule, and that's fine, but it's better for program structure and reliability that such cases be exceptions rather than the usual choice.