【问题标题】:Same C source, different output相同的 C 源,不同的输出
【发布时间】:2023-03-27 06:50:02
【问题描述】:

我找到了几年前实现的旧 C 源代码,以及它编译的二进制可执行文件。

在评论中我写道编译命令是:

gcc -O3 source.c -o executable -lm

所以我重新编译了它,但新的可执行文件与旧的不同(大小)。

事实上,如果我运行新的和旧的可执行文件,它们会给我不同的结果:旧的可执行文件返回几年前返回的相同结果,而新的返回不同的结果。

我的目标是能够重新编译源代码并获得与旧版本相同的可执行文件(或者至少是产生完全相同结果的可执行文件)。

我确定我使用相同的参数运行这两个程序,并且代码确实使用线程。唯一特别的一点是我需要随机整数,但我使用自己的函数来生成它们,以防万一确保随机数的序列始终相同(当然我总是使用相同的种子)。

unsigned int seed = 0;
void set_srand(unsigned int aseed) {
    seed = aseed;
}

int get_rand() {
    seed = seed * 0x12345 + 0xABC123;
    int j = (seed >> 0x10) & RAND_MAX;
    return j;
}

(我以为这是从某个图书馆复制的)。

那会是什么?也许是编译完成的操作系统(原来是在WinXP下,现在我在Win7和Ubuntu下都试过了),但我一直只用MinGW。那么也许是MinGW的版本?如果是这样的话,我就有麻烦了,因为我不记得几年前我使用的是哪个版本。

我使用的库:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

我所做的只是字符串操作和计算,如pow()sqrt()、乘法和加/减,以便应用启发式优化算法来解决近似 NP 难题:结果都是问题,但他们的适应度不同。

【问题讨论】:

  • 你能分享更多关于你的程序产生的输出类型的信息吗?以及版本之间到底有什么不同?
  • 听起来像是代码中的错误。可能依赖未定义或实现特定的行为?
  • @Enne 对于未定义的行为,可能有 2 个不同但正确的结果。但是您没有描述它们有何不同但正确,因此我们没有工具可以帮助您。也就是说,它可能与浮点处理的差异有关。
  • 您是否在做很多浮点运算,并且处理器具有扩展精度(如 Intel)?在这种情况下,结果可能取决于编译器何时溢出到内存,何时不溢出(或者它是否使用较新的 SSE 指令)。
  • @Enne computation like pow(), sqrt() 好吧,如果这些操作是您算法的固有部分,那么在不同版本的编译器上得到不同的结果也就不足为奇了。如果您正在测试浮点计算之间的相等性并且此类测试的结果决定了代码的哪一部分被执行,则尤其如此。

标签: c++ c compilation binary mingw


【解决方案1】:

我要检查的第一件事是 int 的大小。您的代码依赖于溢出,整数的大小可能很重要。

您的代码似乎暗示 int 至少为 32 位(您使用 0x0x269EC3)但也许您现在正在使用 64 位的 int 进行编译。

我不会担心可执行文件,两个不同的编译器不太可能获得相同的大小。

【讨论】:

  • 不,没有“溢出”。算术是unsigned int,它被定义为产生一个特定的结果模下一个更高的二的幂。而且我无法想象 OP 会意外切换到 64 位。不是这个。
  • 我没有说这是一种未定义的行为。 unsigned int 的溢出行为取决于大小。我就是这个意思。
  • 我也没有。我说没有“溢出”。该标准明确表明(引用)“无符号算术不会溢出”。是的,结果取决于大小,但“溢出”仍然与它无关。
猜你喜欢
  • 1970-01-01
  • 2018-01-29
  • 1970-01-01
  • 1970-01-01
  • 2017-03-16
  • 2022-08-13
  • 2021-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多