正如标题中所述,我遇到了一件非常奇怪的事情,就是在Linux上对GCC进行显式和隐式的类型转换。
我有以下简单的代码来演示这个问题:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
int i;
uint32_t e1 = 0;
uint32_t e2 = 0;
const float p = 27.7777;
printf("# e1 (unsigned) e1 (signed) e2 (unsigned) e2 (signed)\n");
for (i = 0; i < 10; i++) {
printf("%d %13u %11d %13u %11d\n", i, e1, e1, e2, e2);
e1 -= (int)p;
e2 -= p;
}
return 0;
}如您所见,e1由p显式类型减少到int,而e2由p隐式类型减少。
我希望e1和e2包含相同的值,但它们不.事实上,结果似乎与系统有关。
为了测试代码,我有两个虚拟机(VirtualBox是从Vagrant开始的)。这是第一台机器:
vagrant@vagrant:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.3 LTS
Release: 16.04
Codename: xenial
vagrant@vagrant:~$ uname -a
Linux vagrant 4.4.0-92-generic #115-Ubuntu SMP Thu Aug 10 16:02:55 UTC 2017 i686 i686 i686 GNU/Linux
vagrant@vagrant:~$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.要构建和执行,我使用以下
vagrant@vagrant:~$ gcc -Wall /vagrant/test.c
vagrant@vagrant:~$ ./a.out
# e1 (unsigned) e1 (signed) e2 (unsigned) e2 (signed)
0 0 0 0 0
1 4294967269 -27 4294967269 -27
2 4294967242 -54 4294967268 -28
3 4294967215 -81 4294967268 -28
4 4294967188 -108 4294967268 -28
5 4294967161 -135 4294967268 -28
6 4294967134 -162 4294967268 -28
7 4294967107 -189 4294967268 -28
8 4294967080 -216 4294967268 -28
9 4294967053 -243 4294967268 -28
vagrant@vagrant:~$如您所见,对于使用显式类型转换的e1来说,一切看起来都很好,但是对于e2来说,结果非常奇怪.
然后,我在另一个虚拟机上尝试了同样的方法,这是Ubuntu的64位版本:
vagrant@ubuntu-xenial:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.3 LTS
Release: 16.04
Codename: xenial
vagrant@ubuntu-xenial:~$ uname -a
Linux ubuntu-xenial 4.4.0-112-generic #135-Ubuntu SMP Fri Jan 19 11:48:36 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
vagrant@ubuntu-xenial:~$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.下面是应用程序的输出:
vagrant@ubuntu-xenial:~$ gcc -Wall /vagrant/test.c
vagrant@ubuntu-xenial:~$ ./a.out
# e1 (unsigned) e1 (signed) e2 (unsigned) e2 (signed)
0 0 0 0 0
1 4294967269 -27 4294967269 -27
2 4294967242 -54 0 0
3 4294967215 -81 4294967269 -27
4 4294967188 -108 0 0
5 4294967161 -135 4294967269 -27
6 4294967134 -162 0 0
7 4294967107 -189 4294967269 -27
8 4294967080 -216 0 0
9 4294967053 -243 4294967269 -27e2的值仍然与我所期望的不一样,但现在与我在32位系统上的值不同了。
我不知道这种差异是由32位对64位造成的,还是与其他相关的。
然而,我想了解为什么在e1和e2上存在差异,以及在发生这种情况时是否有可能至少得到GCC的警告。
谢谢:-)
发布于 2018-01-30 14:13:22
语句e2 -= p等效于e2 = e2 - p。因为e2 - p是一个包含float (e2 = unsigned_val - float_val)的减法,所以这个表达式的计算结果是float,这意味着您实际上要将float值赋值给一个无符号整数变量。
另一个语句e1 -= (int) p不是等价的,因为这里发生的是e1 = unsigned_val - int_val,所以分配给e1的值是一个整数,而不是浮点。
由于将浮点值分配到整数的值超出整数类型范围的整数是未定义的行为(请参见C标准的6.3.1.4实浮点数和整数),因此您在分配给e2时,在不同的平台上都会遇到不同的行为。
https://stackoverflow.com/questions/48523073
复制相似问题