Deutsch English Français Italiano |
<v931ri$4mni$3@dont-email.me> View for Bookmarking (what is this?) Look up another Usenet article |
Path: ...!news.mixmin.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Thiago Adams <thiago.adams@gmail.com> Newsgroups: comp.lang.c Subject: Re: how cast works? Date: Thu, 8 Aug 2024 15:13:06 -0300 Organization: A noiseless patient Spider Lines: 146 Message-ID: <v931ri$4mni$3@dont-email.me> References: <v8vlo9$2oc1v$1@dont-email.me> <slrnvb7kis.28a.dan@djph.net> <v929ah$3u7l7$1@dont-email.me> <v92gt1$e1l$1@dont-email.me> <20240808193203.00006287@yahoo.com> <v92va5$4msg$1@dont-email.me> <v930ga$4mni$1@dont-email.me> <v9316l$4msg$2@dont-email.me> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Injection-Date: Thu, 08 Aug 2024 20:13:07 +0200 (CEST) Injection-Info: dont-email.me; posting-host="c24a25e0e0574963f5160c2b1c68553a"; logging-data="154354"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/v7V1lNVSCjgq/7VhylwN1BcXHcVTSvQU=" User-Agent: Mozilla Thunderbird Cancel-Lock: sha1:HqQ7D4OsxB0UTDJoOuguhcFDAsI= In-Reply-To: <v9316l$4msg$2@dont-email.me> Content-Language: en-US Bytes: 6206 On 08/08/2024 15:01, Bart wrote: > On 08/08/2024 18:50, Thiago Adams wrote: >> On 08/08/2024 14:29, Bart wrote: >>> On 08/08/2024 17:32, Michael S wrote: >>> > On Thu, 8 Aug 2024 14:23:44 +0100 >>> > Bart <bc@freeuk.com> wrote: >>> >> Try godbolt.org. Type in a fragment of code that does different >>> kinds >>> >> of casts (it needs to be well-formed, so inside a function), and see >>> >> what code is produced with different C compilers. >>> >> >>> >> Use -O0 so that the code isn't optimised out of existence, and so >>> >> that you can more easily match it to the C ource. >>> >> >>> >> >>> > >>> > >>> > I'd recommend an opposite - use -O2 so the cast that does nothing >>> > optimized away. >>> > >>> > int foo_i2i(int x) { return (int)x; } >>> > int foo_u2i(unsigned x) { return (int)x; } >>> > int foo_b2i(_Bool x) { return (int)x; } >>> > int foo_d2i(double x) { return (int)x; } >>> The OP is curious as to what's involved when a conversion is done. >>> Hiding or eliminating code isn't helpful in that case; the results >>> can also be misleading: >>> >>> Take this example: >>> >>> void fred(void) { >>> _Bool b; >>> int i; >>> i=b; >>> } >>> >>> Unoptimised, it generates this code: >>> >>> push rbp >>> mov rbp, rsp >>> >>> mov al, byte ptr [rbp - 1] >>> and al, 1 >>> movzx eax, al >>> mov dword ptr [rbp - 8], eax >>> >>> pop rbp >>> ret >>> >>> You can see from this that a Bool occupies one byte; it is masked to >>> 0/1 (so it doesn't trust it to contain only 0/1), then it is widened >>> to an int size. >>> >>> With optimisation turned on, even at -O1, it produces this: >>> >>> ret >>> >>> That strikes me as rather less enlightening! >>> >>> Meanwhile your foo_b2i function contains this optimised code: >>> >>> mov eax, edi >>> ret >>> >>> The masking and widening is not present. Presumably, it is taking >>> advantage of the fact that a _Bool argument will be converted and >>> widened to `int` at the callsite even though the parameter type is >>> also _Bool. So the conversion has already been done. >>> >>> You will see this if writing also a call to foo_b2i() and looking at >>> the /non-elided/ code. >>> >>> The unoptimised code for foo_b2i is pretty awful (like masking twice, >>> with a pointless write to memory between them). But sometimes with >>> gcc there is no sensible middle ground between terrible code, and >>> having most of it eliminated. >>> >>> The unoptimised code from my C compiler for foo_b2i, excluding >>> entry/exit code, is: >>> >>> movsx eax, byte [rbp + foo_b2i.x] >>> >>> My compiler assumes that a _Bool type already contains 0 or 1. >>> >>> >>> >> >> If you are doing constant expression in your compiler, then you have >> the same problem (casts) I am solving in cake. >> >> For instance >> static_assert((unsigned char)1234 == 210); >> >> is already working in my cake. I had to simulate this cast. >> >> Previously, I was doing all computations with bigger types for >> constant expressions. Then I realize compile time must work as the >> runtime. >> >> For constexpr the compiler does not accept initialization invalid types. >> for instance. >> >> constexpr char s = 12345; >> >> <source>:6:21: error: constexpr initializer evaluates to 12345 which >> is not exactly representable in type 'const char' >> 6 | constexpr char s = 12345; >> >> >> I am also checking all wraparound and overflow in constant expressions. >> I have a warning when the computed value is different from the math >> value. > > In my C compiler I have no constexpr (don't know why you got that > impression). And I don't check that initialisers for integer types > overflow their destination. It does not need to be "constexpr" just constant expressions like enum or case of switch. (Cast at compile time is not new in C23.) > This is because within the language in general: > > char c; int i; > > c = i; > > Such an assignment is not checked at runtime (and I don't know if this > can be warned against, or if a runtime check can be added). > > This is just how C works: too-large values are silently truncated (there > are worse aspects of the language, like being able to do `int i; > (&i)[12345];`). But this is something well defined, not UB (I guess). > But you are presumably superimposing a new stricter language on top. In > the case, if my `c = i` assignment was not allowed, how do I get around > that; by a cast? > I am just following C standard. Adding some extra warnings for wraparound.