正如标题中所述,我在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
,结果很奇怪...
然后我在另一个虚拟机上尝试相同的操作,这是一个64位版本的Ubuntu:
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 -27
e2
的值仍然不是我的预期,但现在与我在32位系统上的值不同。
我不知道这种差异是由32位还是64位引起的,或者是否与其他内容有关。
但是,我想了解为什么e1
和e2
存在差异,如果发生这种情况,至少可以从GCC收到警告。
谢谢: - )
答案 0 :(得分:4)
声明e2 -= p
相当于e2 = e2 - p
。由于e2 - p
是涉及float
(e2 = unsigned_val - float_val
)的减法,因此此表达式的计算结果为float
,这意味着您实际上正在为float
赋值e1 -= (int) p
无符号整数变量。
另一个语句e1 = unsigned_val - int_val
不等同,因为这里发生的是e1
,因此分配给e2
的值是整数而不是浮点。
由于将浮点值赋值给整数类型的值超出范围的整数是未定义的行为(参见 6.3.1.4 C的实浮点和整数标准),您在g/\(^\n\|\%1l\).\_.\{-}\n$/execute "normal! vap:call MCformat()\<cr>"
的作业中遇到不同平台的不同行为。