5

abs関数が正しい結果を返さなかったため、テストしていたサンプルコードで問題が発生していました。abs(-2)は-2を出力していました(ちなみに、これが不明な場合は絶対値関数であると考えられます)

少し必死になった後、私は最終的に次のコードを持っていました

#include <stdio.h>

unsigned int abs(int x) {
    return 1;
}

int main() {
    printf("%d\n", abs(-2));
    return 0;
}

これは何の役にも立ちませんが、私の問題を示すのに役立ちます。これは、1を出力することが期待されていたときに、-2を出力していました。

関数名を別の名前(たとえばabs2)に変更すると、結果は正しくなります。また、1つではなく2つの引数を受け取るように変更すると、問題も修正されます。

私の明らかな推測:標準のabs関数との競合。しかし、これでも出力が-2である理由は説明されていません(標準のabs関数を使用している場合は2である必要があります)。両方のバージョンのアセンブリ出力を確認してみました(absおよびabs2という名前の関数を使用)

両方のアセンブリのdiff出力は次のとおりです。

23,25c23,25
< .globl abs
<   .type   abs, @function
< abs:
---
> .globl abs2
>   .type   abs2, @function
> abs2:
54c54
<   .size   abs, .-abs
---
>   .size   abs2, .-abs2
71c71,74
<   movl    -4(%rbp), %edx
---
>   movl    -4(%rbp), %eax
>   movl    %eax, %edi
>   call    abs2
>   movl    %eax, %edx

私が理解していることから、最初のバージョン(関数の名前はabs)は単に関数呼び出しを破棄しているため、abs(x)の代わりにパラメーターxを使用しています。

要約すると、これが発生するのはなぜですか。特に、これに関する警告やエラーを取得する方法が見つからなかったためです。

Debian Squeeze、ggc 4.4.5、およびgcc4.1.2でテスト済み

4

3 に答える 3

7

GCCは、次の相互作用のためにあなたにトリックをプレイしています:

  • abs組み込み関数です。
  • 標準(および組み込み)がabsを返す間に戻ることを宣言しています。unsigned intabssigned int

でコンパイルしてみてくださいgcc -fno-builtin; 私のボックスでは、期待される結果が得られます1。そのオプションを指定せずに、abs戻り値として宣言してコンパイルするsigned intと、プログラムは.を出力します2

(この問題の本当の解決策は、独自の関数にライブラリ識別子を使用しないことです。また、を使用して印刷しないように注意してくださいunsigned int%d

于 2012-04-10T11:34:58.057 に答える
2

gccの呼び出しを最適化してabs()、組み込みのを使用しabs()ます。したがって、このオプションを使用する(またはreturningとして-fno-builtin定義する)と、正しい結果が得られることがわかります。これによると(引用):abs()int

GCCには、標準Cライブラリの多くの関数の組み込みバージョンが含まれています。接頭辞が_builtinのバージョンは、-fno- builtinオプションを指定した場合でも、常にCライブラリ関数と同じ意味を持つものとして扱われます。(C方言オプションを参照)これらの機能の多くは、特定の場合にのみ最適化されます。それらが特定の場合に最適化されていない場合、ライブラリ関数への呼び出しが発行されます。

stdlib.hそもそも宣言するを含めるとabs()、コンパイル時にエラーが発生します。

于 2012-04-10T11:36:59.247 に答える
1

このバグによく似ています。これは2007年のものであり、修正されていると記載されています。

もちろん、GCCの本質を使わずにコンパイルすることを試みる必要があります。つまり、コンパイル時にパスする-fno-builtin(または単に-fno-builtin-absスナイプアウトするabs())必要があります。

于 2012-04-10T11:38:15.113 に答える