Warning: mysqli::__construct(): (HY000/1203): User howardkn already has more than 'max_user_connections' active connections in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\includes\artfuncs.php on line 21
Failed to connect to MySQL: (1203) User howardkn already has more than 'max_user_connections' active connections
Warning: mysqli::query(): Couldn't fetch mysqli in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\index.php on line 66
Article <v93h12$9vom$1@dont-email.me>
Deutsch   English   Français   Italiano  
<v93h12$9vom$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: David Brown <david.brown@hesbynett.no>
Newsgroups: comp.lang.c
Subject: Re: how cast works?
Date: Fri, 9 Aug 2024 00:32:00 +0200
Organization: A noiseless patient Spider
Lines: 231
Message-ID: <v93h12$9vom$1@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>
 <v9310a$4v1a$2@dont-email.me> <v93565$6ffo$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Fri, 09 Aug 2024 00:32:03 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="0e4a7848818310300a2a2b887da8177f";
	logging-data="327446"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX19mhdU3dwDp5assnwPX+jRyBO8hmGuC+wQ="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:eAsin1cDFdC33qHEBvH0/01ogc0=
Content-Language: en-GB, nb-NO
In-Reply-To: <v93565$6ffo$1@dont-email.me>
Bytes: 9174

On 08/08/2024 21:09, Bart wrote:
> On 08/08/2024 18:58, David Brown wrote:
>> On 08/08/2024 19: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:
>>
>> Michael is correct - the OP should enable optimisation, precisely to 
>> avoid the issue you are concerned about.  Without optimisation, the 
>> results are misleading - they will only show things that are /not/ 
>> involved in the conversion, swamping the useful results with code that 
>> messes about putting data on and off the stack.  When optimised 
>> compilation shows that no code is generated, it is a very clear 
>> indication that no operations are needed for the conversions in 
>> question - unoptimized code hides that.
>>
>>>
>>> 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.
>>>
>>
>> No, you can't see that.  All you can see is garbage in, garbage out. 
>> You have to start with a function that has some meaning!
> 
> Sorry but my function is perfectly valid. It's taking a Bool value and 
> converting it to an int.

No, it is not.

Attempting to use the value of a non-static local variable that has not 
been initialised or assigned is undefined behaviour.  Your function is 
garbage.  No one can draw any conclusions about how meaningless code is 
compiled.

> 
> Perhaps you don't understand x86 code? I'll tell you: it loads that 
> /byte-sized/ value, masks it, and widens it to an int. I'm surprised you 
> can't see that.
> 

I understand x86 well enough - perhaps not as well as you, but well 
enough.  I do, however, understand C better than you, it seems.  The x86 
code is irrelevant to the fact that your code has undefined behaviour. 
(And even if it were defined, it would still do nothing relevant.)

> But I suspect a long gaslighting session coming on, where you refute the 
> evidence that everyone else can see!
> 

You are projecting.

Look, it is extraordinarily simple to write functions that /actually/ do 
the conversions under discussion.  Why waste time writing nonsense 
functions that do that?

> 
>>
>>> With optimisation turned on, even at -O1, it produces this:
>>>
>>>          ret
>>
>> Try again with:
>>
>>      int foo(bool x) { return x; }
>>
>>      bool bar(int x) { return x; }
>>
>> Try it with -O0 and -O1, and then tell us which you think gives a 
>> clearer indication of the operations needed.
> 
> Michael is wrong and so are you.
> 
> If you want to know what casting from bool to int entails, then testing 
> it via a function call like this is the wrong way to do it, since half kj
> of it depends on what happens when evaluating arguments at the call site.
> 

Nope.

But if you prefer, just use external variables:

int i;
bool b;

void to_int_0(void) { i = b; }
void to_bool_0(void) { b = i; }

<https://www.godbolt.org/z/eT9Y84Gx4>


Again, look at the two functions with -O0 and -O1, and tell me which is 
clearer.

> Especially if you let the compiler do what it likes, like using its 
> knowledge of that call process, which is not displayed here in the 
> optimised code of the function body.
> 
> 
> So I have some questions of you:
> 
> * How exactly is a _Bool value (which occupies one byte) translated to a 
> 32-bit signed integer? What is involved?
> 

A _Bool is always either 0 or 1.  The conversion is whatever the 
compiler needs to give an int of value 0 or 1.

The implementation details depend entirely on the target.  Typically, if 
the _Bool is in memory, then a single byte is read and zero-extended to 
the width of a register.  If the _Bool is passed to a function as a 
parameter, it is usually already extended - but that will depend on the 
calling conventions.

> This is machine independent other than the sizes mentioned.
>

The specification is independent - it is given by the C standards.  The 
implementation is most certainly not machine independent.  It is also 
not necessarily consistent - compilers can and do pick different code 
depending on the circumstances (where the _Bool came from, and how the 
int is going to be used).  You are even wrong in stating that a _Bool 
occupies one byte, since that is not a requirement for a C 
implementation (though I don't know of any real-world C implementations 
with larger _Bool's).


> Given your answer, how does it correlate with either:
> 
> 
>     mov eax,    edi     ; from your test; both optimised code
> 

Looks fine.
========== REMAINDER OF ARTICLE TRUNCATED ==========