C++ 使用C++;功能参数

C++ 使用C++;功能参数,c++,function,memory-management,calling-convention,C++,Function,Memory Management,Calling Convention,非常简要地提到,当运算符的地址应用于函数块中的一个形式参数时,C(大概是C++)提供了关于连续内存中实际参数位置的保证,而不是寄存器 e、 g 将产生以下输出“1 2 3 4” 我的问题是“这如何与调用约定交互?” 例如,GCC上的\uuuFastCall将尝试将前两个参数放在寄存器中,其余参数放在堆栈中。这两个需求彼此不一致,是否有任何方法可以正式解释将要发生的事情,或者是否受制于实现定义行为的反复无常性 更新:我想这个问题已经得到了回答。我认为我把整个问题建立在连续内存分配的基础上是错误的

非常简要地提到,当运算符的地址应用于函数块中的一个形式参数时,C(大概是C++)提供了关于连续内存中实际参数位置的保证,而不是寄存器

e、 g

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

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

例如,GCC上的\uuuFastCall将尝试将前两个参数放在寄存器中,其余参数放在堆栈中。这两个需求彼此不一致,是否有任何方法可以正式解释将要发生的事情,或者是否受制于实现定义行为的反复无常性

更新:我想这个问题已经得到了回答。我认为我把整个问题建立在连续内存分配的基础上是错误的,因为我所寻找的(以及参考文献所提到的)是内存中的参数需求(由于使用的地址)与寄存器中的参数需求(由于调用约定)之间的明显不匹配,这可能是另一天的问题


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

首先,您的代码并不总是生成1、2、3、4。只需检查一下这个: 正确的代码至少类似于:

结果很混乱:
1-1216913420 134514560 134514524


所以我真的怀疑这里是否有什么可以保证。

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

1-680135568327674196336


使用<代码> g++(ubuntu4.4.3-4ubuntu5)4.4.3 64位x86。< /p> < p> C++标准没有调用约定的概念。这是留给编译器处理的

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


由编译器决定做什么。但是,我认为大多数编译器会将您的需求置于标准之上。

标准中没有关于调用约定或参数传递方式的内容

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


它肯定不会影响其他变量,谁的地址不会被记录。

事实上,
cout
表达式没有很好的定义(因为您正在更改并请求
p
),所以结果可能是偶然的:)@DuncanACoulter当然,这种行为是给定实现的伪迹,而不是由C/C++语言标准保证的?@ DunCaCurter:一种简单的方法是让编译器诊断调用约定在要求(在函数的定义点)是奇数,因为我们这里说的是C/C++。我不想冒险进入这个领域,或者我已经编辑了这个问题,不再使用单一的输出表达式。然而,根本问题仍然存在,这确实是一种可能性,有时,可以对规则进行明确的解释,这正是我在这里所希望的。从单个表达式到循环的移动必须是在您格式化答复时进行的。我接受此处给出的反例的实现级别反证。这似乎是高度特定于实现的。遗憾的是,似乎没有一种方法可以在不诉诸探索性测试的情况下预先确定需求如何交互。@DuncanACoulter我认为这不是一种需求。许多ABI x64、alpha、itanium等理所当然地传递了寄存器中的前N个参数。我能想到的唯一一种情况是,在您认为需要它的地方,应该是varargs,但使用诸如注册窗口之类的功能,您不一定需要它。我怀疑是Appel弄错了,过时了,还是您误读了或误解了声明。如果你引用他的话,也许你能得到一个更好的答案。即使这是真的,您的代码也取决于堆栈增长的方向和参数推送的顺序。@Logan Capaldo更新了问题,包括通过Google Books链接到精确引用的链接。@DuncanACoulter您链接的书中的引用根本没有说任何关于连续内存的内容。它甚至说“一个工业实力编译器必须将临时位置分配给正式的和本地的,然后决定哪一个应该真正进入寄存器”,明确地允许一些东西进入寄存器,而另一些东西不进入寄存器,并且对连续性只字未提。我想你误解了这里的内容。
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);
void foo(int a, int b, int c, int d)
{
    int* p = &a;
    for (int i = 0; i < 4; i++)
    {
        std::cout << *p;
        p++;
    }
}
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);
}