Path: ...!2.eu.feeder.erje.net!feeder.erje.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: David Brown Newsgroups: comp.lang.c Subject: Re: No warning at implicit removal of const. Was: relearning C: why does an in-place change to a char* segfault? Date: Sat, 3 Aug 2024 19:54:20 +0200 Organization: A noiseless patient Spider Lines: 83 Message-ID: References: <20240801174026.00002cda@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Sat, 03 Aug 2024 19:54:23 +0200 (CEST) Injection-Info: dont-email.me; posting-host="b209585f2ada3beb09365cfb8283ed97"; logging-data="3743763"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18uIlLlMa85CueVcvsc4zecBIjHPNixs2o=" User-Agent: Mozilla Thunderbird Cancel-Lock: sha1:KkijRPbx9eV6Sgu9U4QLhitOTHA= Content-Language: en-GB, nb-NO In-Reply-To: Bytes: 4809 On 02/08/2024 07:30, candycanearter07 wrote: > David Brown wrote at 17:56 this Thursday (GMT): >> On 01/08/2024 16:40, Michael S wrote: >>> On Thu, 01 Aug 2024 08:06:57 +0000 >>> Mark Summerfield wrote: >>> >>>> This program segfaults at the commented line: >>>> >>>> #include >>>> #include >>>> >>>> void uppercase_ascii(char *s) { >>>> while (*s) { >>>> *s = toupper(*s); // SEGFAULT >>>> s++; >>>> } >>>> } >>>> >>>> int main() { >>>> char* text = "this is a test"; >>>> printf("before [%s]\n", text); >>>> uppercase_ascii(text); >>>> printf("after [%s]\n", text); >>>> } >>>> >>> >>> The answers to your question are already given above, so I'd talk about >>> something else. Sorry about it. >>> >>> To my surprise, none of the 3 major compilers that I tried issued the >>> warning at this line: >>> char* text = "this is a test"; >>> If implicit conversion of 'const char*' to 'char*' does not warrant >>> compiler warning than I don't know what does. >>> Is there something in the Standard that explicitly forbids diagnostic >>> for this sort of conversion? >>> >>> BTW, all 3 compilers issue reasonable warnings when I write it slightly >>> differently: >>> const char* ctext = "this is a test"; >>> char* text = ctext; >>> >>> I am starting to suspect that compilers (and the Standard?) consider >>> string literals as being of type 'char*' rather than 'const char*'. >>> >> >> Your suspicions are correct - in C, string literals are used to >> initialise an array of char (or wide char, or other appropriate >> character type). Perhaps you are thinking of C++, where the type is >> "const char" (or other const character type). >> >> So in C, when a string literal is used in an expression it is converted >> to a "char *" pointer. You can, of course, assign that to a "const char >> *" pointer. But it does not make sense to have a warning when assigning >> it to a non-const "char *" pointer. This is despite it being undefined >> behaviour (explicitly stated in the standards) to attempt to write to a >> string literal. >> >> The reason string literals are not const in C is backwards compatibility >> - they existed before C had "const", and making string literals into >> "const char" arrays would mean that existing code that assigned them to >> non-const pointers would then be in error. C++ was able to do the right >> thing and make them arrays of const char because it had "const" from the >> beginning. >> >> gcc has the option "-Wwrite-strings" that makes string literals in C >> have "const char" array type, and thus give errors when you try to >> assign to a non-const char * pointer. But the option has to be >> specified explicitly (it is not in -Wall) because it changes the meaning >> of the code and can cause compatibility issues with existing correct code. > > > -Wwrite-strings is included in -Wpedantic. No, it is not - which is a good thing, because -Wpedantic should not include features that change the semantics of the language! (IMHO the flag should not be called -Wwrite-strings, but -fconst-string-literals or similar. It's not really a normal warning option.) For C++, -pedantic-errors includes the -Wwrite-strings flag which then makes implicit conversion of string literal expressions to non-const char* pointers an error. But that's C++, not C.