Sujet : Re: how cast works?
De : bc (at) *nospam* freeuk.com (Bart)
Groupes : comp.lang.cDate : 08. Aug 2024, 20:09:56
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <v93565$6ffo$1@dont-email.me>
References : 1 2 3 4 5 6 7
User-Agent : Mozilla Thunderbird
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.
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.
But I suspect a long gaslighting session coming on, where you refute the evidence that everyone else can see!
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 of it depends on what happens when evaluating arguments at the call site.
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?
This is machine independent other than the sizes mentioned.
Given your answer, how does it correlate with either:
mov eax, edi ; from your test; both optimised code
<nothing> ; from my test
The advantage of unoptimised code is that it will contain everything that is normally involved; it doesn't throw anything away.
It doesn't require convincing the compiler that you're doing something useful to avoid it eliminating most or all your code, or turning it something that is just plain misleading.
That might be useful when compiling a huge production version of an app, but it is useless when trying to shed light on an isolated fragment of code.
Look, just forget it, I'm not in the mood for another marathon subthread.
So, what's involved in turning Bool to int? According to your examples with -O1: nothing. You just copy 32 bits unchanged from one to the other. Mildly surprising, but you are of course right, right?
However, now *I* have a problem, figuring out why on earth C compiler does the conversion like this:
movsx eax, byte [source]
Because this must be wrong, right?