问题
Consider this code:
#include <stdio.h>
int main(void)
{
/* TEST 1 */
double d = 128;
char ch = (char)d;
printf("%d\n", ch);
/* TEST 2 */
printf("%d\n", (char)128.0);
/* TEST 3 */
char ch1 = (char)128.0;
printf("%d\n", ch1);
return 0;
}
Results:
gcc* clang* cl*
TEST 1 -128 -128 -128
TEST 2 127 0 -128
TEST 3 127 -2 -128
* latest version
Questions:
- Why the results differ between tests (excluding
cl
)? - Why the results differ between compilers (excluding
TEST 1
)? - In case of UB/IB, where is the UB/IB exactly? What the standard says?
- [Extra question] Why
clang
shows so different behavior? Where these0
and-2
come from?
回答1:
When CHAR_MAX == 127
, (char)128.0
is undefined behavior (UB).
When a finite value of real floating type is converted to an integer type other than
_Bool
, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined. C17dr § 6.3.1.4 1
This is not UB due to integer overflow. It is UB due to conversion rules.
回答2:
AS @chux stated (char)128.0
is an UB. gcc because the triviality of the example detects this UB and instead takes CHAR_MAX as largest closest signed number.
But if you confuse it a bit it will not behave like this (conversion to int is not an UB, and the next conversion UB is not detected by the gcc).
int main(void)
{
volatile char x = (char)128.0;
volatile char y = (char)(int)128.0;
printf("%d %d\n", x, y);
}
and the code (the interesting part):
mov BYTE PTR [rsp+14], 127
mov BYTE PTR [rsp+15], -128
https://godbolt.org/z/xG3jUy
BTW this gcc behaviour was discussed long time ago and many people (including me) were opposing it. But gcc developers decided to go this way.
来源:https://stackoverflow.com/questions/62682244/type-casting-double-to-char-multiple-questions