gcc

时间:2018-01-30 13:49:58

标签: c gcc

正如标题中所述,我在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隐式地进行了类型化。

我希望e1e2包含相同的值,但它们不会......实际上,结果看起来与系统有关。

为了测试代码,我有两个虚拟机(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位引起的,或者是否与其他内容有关。

但是,我想了解为什么e1e2存在差异,如果发生这种情况,至少可以从GCC收到警告。

谢谢: - )

1 个答案:

答案 0 :(得分:4)

声明e2 -= p相当于e2 = e2 - p。由于e2 - p是涉及floate2 = 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>" 的作业中遇到不同平台的不同行为。