10

Appel [App02]非常简要地提到,当地址操作符应用于功能块内的形式参数之一时,C(并且可能是 C++)提供了关于实际参数在连续内存中的位置的保证,而不是寄存器。

例如

void foo(int a, int b, int c, int d)
{
    int* p = &a;
    for(int k = 0; k < 4; k++)
    {
       std::cout << *p << " ";
       p++;
    }
    std::cout << std::endl;
}

和一个调用,如......

foo(1,2,3,4);

将产生以下输出“1 2 3 4”

我的问题是“这如何与调用约定交互?”

例如,GCC 上的 __fastcall 将尝试将前两个参数放在寄存器中,将其余参数放在堆栈中。这两个要求相互矛盾,有什么方法可以正式推断会发生什么,或者它是否受制于实现定义行为的反复无常的性质?

[App02] Java 中的现代编译器实现,Andrew w. 上诉,第 6 章,第 124 页

更新:我想这个问题已经回答了。我认为我将整个问题建立在连续内存分配上是错误的,因为我正在寻找(以及参考所说的)是由于使用 address-of 而在内存中的参数需求之间的明显不匹配,而不是由于调用约定而在寄存器中,也许这是另一天的问题。

互联网上的某个人是错误的,有时有人是我。

4

4 回答 4

3

首先,您的代码并不总是产生 1、2、3、4。只需检查一下:http: //ideone.com/ohtt0 正确的代码至少是这样的:

void foo(int a, int b, int c, int d)
{
    int* p = &a;
    for (int i = 0; i < 4; i++)
    {
        std::cout << *p;
        p++;
    }
}

所以现在让我们在这里尝试一下fastcall

void __attribute__((fastcall)) foo(int a, int b, int c, int d)
{
    int* p = &a;
    for (int i = 0; i < 4; i++)
    {
        std::cout << *p << " ";
        p++;
    }
}

int main()
{
        foo(1,2,3,4);
}

结果很乱:1 -1216913420 134514560 134514524

所以我真的怀疑这里能保证什么。

于 2011-03-29T11:47:21.243 回答
1

C++ 标准没有调用约定的概念。这留给编译器处理。

在这种情况下,如果标准要求在应用地址运算符时参数是连续的,则标准对编译器的要求与您对它的要求之间存在冲突。

由编译器决定做什么。但是,我认为大多数编译器会将您的要求优先于标准。

于 2011-03-29T11:49:54.793 回答
1

标准中没有关于调用约定或如何传递参数的内容。

确实,如果您获取一个变量(或参数)的地址,则必须将其存储在内存中。这并不是说该值不能在寄存器中传递,然后在获取其地址时存储到内存中。

它绝对不会影响其他变量,谁的地址没有被占用。

于 2011-03-29T11:59:50.603 回答
0

你的基本假设是有缺陷的。在我的机器上,foo(1,2,3,4)使用您的代码打印出:

1 -680135568 32767 4196336

g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3在 64 位 x86 上使用。

于 2011-03-29T11:48:49.350 回答