10

Appel [App02]は、アドレス演算子が関数ブロック内の仮パラメーターの1つに適用される場合、レジスターではなく、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);

次の出力「1234」が生成されます

私の質問は、「これは呼び出し規約とどのように相互作用するのですか?」です。

たとえば、GCCの__fastcallは、最初の2つの引数をレジスタに配置し、残りをスタックに配置しようとします。2つの要件は互いに対立していますが、何が起こるかについて正式に推論する方法はありますか、それとも実装で定義された動作の気まぐれな性質の影響を受けますか?

[App02] Javaでの最新のコンパイラ実装、Andreww。Appel、第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

標準には、呼び出し規約やパラメーターの受け渡し方法については何もありません。

確かに、1つの変数(またはパラメーター)のアドレスを取得する場合、その1つをメモリーに保管する必要があります。値がレジスタに渡され、そのアドレスが取得されたときにメモリに格納できないということではありません。

それは間違いなく他の変数に影響を与えません、誰のアドレスは取られません。

于 2011-03-29T11:59:50.603 に答える
1

C ++標準には、呼び出し規約の概念はありません。それはコンパイラが処理するために残されています。

この場合、address-of演算子が適用されるときにパラメーターが連続していることが標準で要求されている場合、標準がコンパイラーに要求するものと、それを要求するものとの間に矛盾があります。

何をすべきかを決めるのはコンパイラー次第です。ただし、ほとんどのコンパイラは、標準よりも要件を優先すると思います。

于 2011-03-29T11:49:54.793 に答える
0

あなたの基本的な仮定には欠陥があります。私のマシンではfoo(1,2,3,4)、コードを使用すると次のように出力されます。

1 -680135568 32767 4196336

g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.364ビットx86で使用します。

于 2011-03-29T11:48:49.350 に答える