gpt4 book ai didi

c - VS2010 中具有无参数原型(prototype)和 64 位架构的前 ANSI C,第二个和第三个参数消失

转载 作者:行者123 更新时间:2023-12-02 01:52:07 25 4
gpt4 key购买 nike

我知道这很奇怪,但还是这样。

我正在管理一个非常古老的 ANSI C 之前的代码库。不管你信不信,下面的代码实际上是可以编译的。

myprog.c:

// Prototype.
int rec_index(); // Zero arguments.

kz = rec_index(1, 19, 2, 0, " ", 0, -1); // Seven arguments.

recindex.c:

int rec_index(flag, type, from, to, c, s, status, t)       // Eight arguments.
int flag, type, from, to, s, status, t;
char *c;
{
printf("%d %d %d", flag, type, from);

if (flag < 0 || flag > 2) {
return -1;
}

if (type < 1 || type > 20) { // Line A.
return -1;
}

if ((flag == 1) && (type < 7 || type == 12 || type == 13)) { // Line B.
// Line C.
}
}

在 32 位环境中,这表现相当不错。函数定义中缺少的参数 t 被解释为零(或者更准确地说,它是未定义的),但这只包含在对该函数的一小部分调用中,而早已离开的开发人员知道在需要时包括在内。因此,当运行此代码时,输​​出将如预期的那样是前三个参数:

1 19 2

太棒了。该方法返回预期的行为。

但是……

我们最近开始将我们的软件移植到 64 位环境。在 64 位配置中,无论传递给函数的是什么,8 的第二个和第三个参数在函数中都被读取为零

所以,在函数调用中传入1、19、2,检查函数内部的参数,Visual Studio报告为1、0、0。

1 0 0

奇怪的是,第四到第八个参数正确通过。只有第二个和第三个是错误的。

这就像站在某人旁边,拿一个空钱包,放入 3 美元,递给他们,他们打开钱包发现里面是空的。值(value)观去了哪里?

但它变得陌生了。我将 type 作为 19 传入,但该函数报告其值为零。 (这是通过检查内存位置 &type 来支持的。)让我们先看一下。

现在我们来到 recindex.c 中标记为 A 行的 if 语句:

    if (type < 1 || type > 20) {         // Line A.

由于调试器报告 type 为零,因此 || 的左侧应该为真,这将使整个 bool 值短路为真,跳入大括号并导致 return -1;。奇怪的是,这没有发生,调试器跳转到 B 行的下一个 if:

    if ((flag == 1) && (type < 7 || type == 12 || type == 13)) {     // Line B.

同样,type 应该为零,flag(实际上保持不变)为 1。这应该使整个 if 条件为真, 并陷入到 C 行的循环中。

指令指针按预期跳入循环,但 type 的值从 0 变为某个较大的值,始终不同,大约在 5000000 左右。 if 条件中的 NOTHING 有任何副作用,那么这个值是如何变化的?!

我猜想发生了某种堆栈损坏,这可能是由于非常不一致的函数原型(prototype)设计导致的未定义行为的结果。同样,这实际上在 32 位环境中有效,并且已经使用了 20 多年。

这里正确的答案是重写函数调用,以便全部采用八个参数,匹配函数声明,并使用像 int32_t 这样的类型而不是 int 所以我们可以确定尺寸。我可能会这样做。

但是,我很想解释为什么我会看到我现在的行为。

  • 为什么输入函数后,函数的第二个和第三个参数被重写为零?

  • 为什么其中一个参数的值虽然看起来为零,但在计算时却不像零?

  • 当没有什么可以改变它时,是什么导致该值发生变化?

最佳答案

我想通了。

我提到(有点混淆)我正在调用这个函数:

int rec_index(flag, type, from, to, ck, sec, status, tert)
int flag, type, from, to, sec, status, tert;
char *ck;
{ … }

在我写的帖子中,对这个函数的调用是这样的:

  kz = rec_index(1, 19, 2, 0, "  ", 0, -1);                  // Seven arguments.

但为了避免在公共(public)互联网论坛上分享太多内部片段,我实际上解释了这个,真正的代码:

kz = rec_index(1, 19, trp->iztabl, 0, "  ", 0, -1);

我假设不一致的原型(prototype)导致了损坏。当然不是——真正的问题在于第三个参数,trp->iztabl。变量 trpstruct tran * 类型,一个指向结构的指针。在反省实际值并尝试取消引用它时,我发现 trp 是一个错误的指针。不是 NULL 指针,而是 BAD 指针——只是乱码,指向未知的内存区域。

当目标代码遇到一个错误的指针时,它要么不知道如何使用箭头运算符,要么更可能的是,它会转到由 trp 指定的内存中的适当位置并向前跳转与 iztabl 在结构中的位置对应的字节数。不过,人们会认为这只会返回乱码。

问题/编译器错误/普遍的烦恼是箭头运算符应用失败返回的值是一个 64 位指针,因为我们处于 64 位环境中,而不是 32 位 int trp->iztabl 已定义。由于对 rec_index() 的调用由彼此相邻的 32 位整数组成,因此插入 64 位指针的行为具有破坏性。这就是第二个和第三个参数消失的原因。 trp->iztabl 的返回值取出它自己的内存位置和它之前的那个(由于字节顺序)。

我看到的其他行为与值在调试器中被覆盖有关。我怀疑调试器的预期行为与此代码提供的不同,因此它在运行时感到困惑。

关于c - VS2010 中具有无参数原型(prototype)和 64 位架构的前 ANSI C,第二个和第三个参数消失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22184851/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com