【问题标题】:Why do these two files have different hex outputs?为什么这两个文件有不同的十六进制输出?
【发布时间】:2016-11-02 02:55:46
【问题描述】:

我正在经历 K&R 并决定做一个实验。在 K&R 中,首先教导 while 循环,然后教导 for 循环。在这样做的过程中,同一个程序是用while 循环和for 循环编写的。这些程序都有相同的输出并且在功能上做同样的事情。然后我想用vim -d <(xxd celsius) <(xxd ccelsius)比较两个二进制文件,并认为它们是同一个文件;但是,它们不是。虽然文件的某些部分相同,但也存在显着差异。我想知道为什么存在这些差异,以及是否有任何方法可以使文件编译为相同的二进制文件。我使用gcc 作为我的编译器。

C 文件

摄氏度.c

#include <stdio.h>

/* print Fahrenheit-Celsius table
 *  for fahr = 0, 20, ..., 300; floating-point version */
int main(void)
{
    float fahr, celsius;
    int lower, upper, step;

    lower = 0;  /* lower limit of temperature table */
    upper = 300;    /* upper limit */
    step = 20;  /* step size */

    fahr = lower;
    while (fahr <= upper) {
        celsius = (5.0/9.0) * (fahr-32.0);
        printf("%3.0f %6.1f\n", fahr, celsius);
        fahr = fahr + step;
    }
}

ccelcius.c

#include <stdio.h>

/* print Fahrenheit-Celsius table */
int main(void)
{
    float fahr;

    for (fahr = 0; fahr <= 300; fahr = fahr + 20)
        printf("%3.0f %6.1f\n", fahr, (5.0/9.0)*(fahr-32));
}

十六进制差异文件

diff &lt;(xxd celsius) &lt;(xxd ccelsius)

14,15c14,15
< 000000d0: c00e 0000 0100 0000 a700 0000 0000 0000  ................
< 000000e0: c00e 0000 0400 0000 0000 0000 0000 0000  ................
---
> 000000d0: e00e 0000 0100 0000 8d00 0000 0000 0000  ................
> 000000e0: e00e 0000 0400 0000 0000 0000 0000 0000  ................
19,20c19,20
< 00000120: 680f 0000 0100 0000 0600 0000 0000 0000  h...............
< 00000130: 680f 0000 0100 0000 0000 0000 0000 0000  h...............
---
> 00000120: 6e0f 0000 0100 0000 0600 0000 0000 0000  n...............
> 00000130: 6e0f 0000 0100 0000 0000 0000 0000 0000  n...............
24,25c24,25
< 00000170: 700f 0000 0100 0000 1a00 0000 0000 0000  p...............
< 00000180: 700f 0000 0200 0000 0000 0000 0000 0000  p...............
---
> 00000170: 740f 0000 0100 0000 1a00 0000 0000 0000  t...............
> 00000180: 740f 0000 0200 0000 0000 0000 0000 0000  t...............
29c29
< 000001c0: 900f 0000 0100 0000 0c00 0000 0000 0000  ................
---
> 000001c0: 900f 0000 0100 0000 1800 0000 0000 0000  ................
34,35c34,35
< 00000210: 9c0f 0000 0100 0000 0d00 0000 0000 0000  ................
< 00000220: 9c0f 0000 0000 0000 0000 0000 0000 0000  ................
---
> 00000210: a80f 0000 0100 0000 0b00 0000 0000 0000  ................
> 00000220: a80f 0000 0000 0000 0000 0000 0000 0000  ................
39,40c39,40
< 00000260: ac0f 0000 0100 0000 4800 0000 0000 0000  ........H.......
< 00000270: ac0f 0000 0200 0000 0000 0000 0000 0000  ................
---
> 00000260: b40f 0000 0100 0000 4800 0000 0000 0000  ........H.......
> 00000270: b40f 0000 0200 0000 0000 0000 0000 0000  ................
73c73
< 00000480: 1985 c866 b4a1 304e 965d 4a68 80be 0434  ...f..0N.]Jh...4
---
> 00000480: 37e9 3480 21a8 3e96 b783 ea6a 3feb 00d8  7.4.!.>....j?...
76c76
< 000004b0: 2800 0080 1800 0000 c00e 0000 0000 0000  (...............
---
> 000004b0: 2800 0080 1800 0000 e00e 0000 0000 0000  (...............
237,256c237,256
< 00000ec0: 5548 89e5 4883 ec20 c745 fc00 0000 00c7  UH..H.. .E......
< 00000ed0: 45f0 0000 0000 c745 ec2c 0100 00c7 45e8  E......E.,....E.
< 00000ee0: 1400 0000 f30f 2a45 f0f3 0f11 45f8 f30f  ......*E....E...
< 00000ef0: 1045 f8f3 0f2a 4dec 0f2e c80f 825d 0000  .E...*M......]..
< 00000f00: 0048 8d3d 9400 0000 f20f 1005 8000 0000  .H.=............
< 00000f10: f30f 100d 8000 0000 f30f 1055 f8f3 0f5c  ...........U...\
< 00000f20: d1f3 0f5a caf2 0f59 c1f2 0f5a c0f3 0f11  ...Z...Y...Z....
< 00000f30: 45f4 f30f 5a45 f8f3 0f5a 4df4 b002 e825  E...ZE...ZM....%
< 00000f40: 0000 00f3 0f10 45f8 f30f 2a4d e8f3 0f58  ......E...*M...X
< 00000f50: c1f3 0f11 45f8 8945 e4e9 90ff ffff 8b45  ....E..E.......E
< 00000f60: fc48 83c4 205d c390 ff25 a200 0000 0000  .H.. ]...%......
< 00000f70: 4c8d 1d91 0000 0041 53ff 2581 0000 0090  L......AS.%.....
< 00000f80: 6800 0000 00e9 e6ff ffff 0000 0000 0000  h...............
< 00000f90: 721c c771 1cc7 e13f 0000 0042 2533 2e30  r..q...?...B%3.0
< 00000fa0: 6620 2536 2e31 660a 0000 0000 0100 0000  f %6.1f.........
< 00000fb0: 1c00 0000 0000 0000 1c00 0000 0000 0000  ................
< 00000fc0: 1c00 0000 0200 0000 c00e 0000 3400 0000  ............4...
< 00000fd0: 3400 0000 680f 0000 0000 0000 3400 0000  4...h.......4...
< 00000fe0: 0300 0000 0c00 0100 1000 0100 0000 0000  ................
< 00000ff0: 0000 0001 0000 0000 0000 0000 0000 0000  ................
---
> 00000ec0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00000ed0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00000ee0: 5548 89e5 4883 ec20 0f57 c0c7 45fc 0000  UH..H.. .W..E...
> 00000ef0: 0000 f30f 1145 f8f3 0f10 0591 0000 000f  .....E..........
> 00000f00: 2e45 f80f 825b 0000 0048 8d3d 9800 0000  .E...[...H.=....
> 00000f10: f20f 1005 8800 0000 f30f 100d 7400 0000  ............t...
> 00000f20: f30f 5a55 f8f3 0f10 5df8 f30f 5cd9 f30f  ..ZU....]...\...
> 00000f30: 5acb f20f 59c1 f20f 1145 f00f 28c2 f20f  Z...Y....E..(...
> 00000f40: 104d f0b0 02e8 2400 0000 8945 ecf3 0f10  .M....$....E....
> 00000f50: 0543 0000 00f3 0f58 45f8 f30f 1145 f8e9  .C.....XE....E..
> 00000f60: 93ff ffff 8b45 fc48 83c4 205d c390 ff25  .....E.H.. ]...%
> 00000f70: 9c00 0000 4c8d 1d8d 0000 0041 53ff 257d  ....L......AS.%}
> 00000f80: 0000 0090 6800 0000 00e9 e6ff ffff 0000  ....h...........
> 00000f90: 0000 9643 0000 0042 0000 a041 0000 0000  ...C...B...A....
> 00000fa0: 721c c771 1cc7 e13f 2533 6420 2536 2e31  r..q...?%3d %6.1
> 00000fb0: 660a 0000 0100 0000 1c00 0000 0000 0000  f...............
> 00000fc0: 1c00 0000 0000 0000 1c00 0000 0200 0000  ................
> 00000fd0: e00e 0000 3400 0000 3400 0000 6e0f 0000  ....4...4...n...
> 00000fe0: 0000 0000 3400 0000 0300 0000 0c00 0100  ....4...........
> 00000ff0: 1000 0100 0000 0000 0000 0001 0000 0000  ................
258c258
< 00001010: 800f 0000 0100 0000 0000 0000 0000 0000  ................
---
> 00001010: 840f 0000 0100 0000 0000 0000 0000 0000  ................
518,519c518,519
< 00002050: 2502 0000 0003 00c0 1d00 0000 0000 0000  %...............
< 00002060: c01d 0000 0000 0000 0200 0000 0f01 1000  ................
---
> 00002050: 2502 0000 0003 00e0 1d00 0000 0000 0000  %...............
> 00002060: e01d 0000 0000 0000 0200 0000 0f01 1000  ................
521c521
< 00002080: c00e 0000 0100 0000 1c00 0000 0100 0001  ................
---
> 00002080: e00e 0000 0100 0000 1c00 0000 0100 0001  ................

【问题讨论】:

  • -S 编译得到两个程序的汇编代码。汇编代码的区别会更容易理解。
  • @user3386109 我确实这样做了。不幸的是,我不太了解汇编,但它比十六进制要清楚得多。不过,我肯定会做得更多。我真的有助于了解程序的实际外观。
  • 编译器并不完美。他们不会产生最好的二进制文件(假设存在给定源程序的最佳二进制版本)。它们只是产生源程序的正确二进制表示,并且有许多不同的二进制文件可以产生相同的输出。因此,如果您为编译器提供两个不同的源程序,那么您将获得不同的二进制文件也就不足为奇了。
  • cc 不是特定的编译器,而是系统默认使用的别名。
  • @Olaf 哎呀。我会解决的。 cc 是我机器上 gcc 的别名。

标签: c gcc hex


【解决方案1】:

在第一个例子中

celsius = (5.0/9.0) * (fahr-32.0);

正在使用double 计算结果,然后将其截断为float,然后将其提升回double 以使用%f 格式打印。

在第二个例子中,计算再次使用double

printf("%3.0f %6.1f\n", fahr, (5.0/9.0)*(fahr-32));

但是float 没有截断,因为double 是预期的。所以计算结果略有不同。

【讨论】:

  • 那么,如果我将(5.0/9.0)*(fahr-32) 转换为float,它们会是一样的吗?
  • 如果我将上述表达式转换为float,两个二进制文件仍然存在差异。这是否与 C 截断的方式有关?
  • 我会避开(尝试一下)并建议您停止使用 20 世纪书籍中的 float 并使用 double,除非有令人信服的理由不这样做。
  • 总的来说,我几乎不使用float,我只是在经历K&R时使用它。
  • 我确实经常看到这些链接。我知道浮点数学没有被破坏,我更想知道如果强制转换是隐式还是显式,C 是否使用不同的截断标准。感谢您帮助解释这一点!
【解决方案2】:

如果您对反汇编进行比较,即使二进制文件不完全匹配,在编译时优化后的结果也几乎相同(由于 Weather Vane 的 cmets,我已将两个源文件更改为专门使用浮点数):

celsius.c

#include <stdio.h>

/* print Fahrenheit-Celsius table
 *  for fahr = 0, 20, ..., 300; floating-point version */
int main(void)
{
    float fahr, celsius;
    static const int lower = 0;
    static const int upper = 300;
    static const int step = 20;

    fahr = lower;
    while (fahr <= upper) {
        celsius = (5.0f/9.0f) * (fahr-32.0f);
        printf("%3.0f %6.1f\n", fahr, celsius);
        fahr = fahr + step;
    }
}

ccelsius.c

#include <stdio.h>

/* print Fahrenheit-Celsius table */
int main(void)
{
    float fahr;

    for (fahr = 0; fahr <= 300; fahr = fahr + 20)
        printf("%3.0f %6.1f\n", fahr, (5.0f/9.0f)*(fahr-32.0f));
}

编译 cc -Wall -O3 摄氏度.c -o 摄氏度 && cc -Wall -O3 ccelsius.c -o 摄氏度

差异

2c2
< celsius:     file format elf64-x86-64
---
> ccelsius:     file format elf64-x86-64

【讨论】:

  • 即使使用 -O1 而不是 -O3 也会给我同样的结果。
  • 谢谢!优化是我首先缺少的。一开始我忘了优化,但是优化后它们是一样的。
  • C 没有符号常量(enum-constants 除外)。仅这一点可能会有所作为。它使用宏来模拟它们。
  • @Olaf 你所说的符号常量是什么意思?
  • @Olaf 当我查看它时,我发现的只是 C 中的符号常量。这就是为什么我认为我可能一直在寻找错误的术语。您的意思是类似于 C++ 中的 const 可以是符号常量,而 C 中的 const 不提供该功能?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-02
  • 1970-01-01
相关资源
最近更新 更多