2017-10-05 9 views
2

C99およびC11の有効タイプルールでは、宣言されたタイプのない記憶領域は任意のタイプで書き込まれ、非文字タイプの値を格納すると、それに応じて記憶領域の有効タイプが設定されることが規定されています。この実効タイプルールの使用は厳密に準拠していますか?

INT_MAXが123456789未満である可能性を除いて、次のコードの有効なタイプルールの使用は厳密に適合するでしょうか?

#include <stdlib.h> 
#include <stdio.h> 

/* Performs some calculations using using int, then float, 
    then int. 

    If both results are desired, do_test(intbuff, floatbuff, 1); 
    For int only, do_test(intbuff, intbuff, 1); 
    For float only, do_test(floatbuff, float_buff, 0); 

    The latter two usages require storage with no declared type.  
*/ 

void do_test(void *p1, void *p2, int leave_as_int) 
{ 
    *(int*)p1 = 1234000000; 

    float f = *(int*)p1; 
    *(float*)p2 = f*2-1234000000.0f; 

    if (leave_as_int) 
    { 
    int i = *(float*)p2; 
    *(int*)p1 = i+567890; 
    } 
} 

void (*volatile test)(void *p1, void *p2, int leave_as_int) = do_test; 

int main(void) 
{ 
    int iresult; 
    float fresult; 
    void *p = malloc(sizeof(int) + sizeof(float)); 
    if (p) 
    { 
    test(p,p,1); 
    iresult = *(int*)p; 
    test(p,p,0); 
    fresult = *(float*)p; 
    free(p); 
    printf("%10d %15.2f\n", iresult,fresult); 
    } 
    return 0; 
} 

標準の私の読書から、コメントで説明した機能のすべての3つの用途は、厳密には(整数範囲の問題を除く)準拠する必要があります。コードは1234567890 1234000000.00を出力するはずです。しかし、GCC 7.2は、1234056789 1157904.00を出力します。私はleave_as_intが0の場合、123400000.0fを*p2に格納した後、123400000を*p1に格納していますが、このような動作を許可するものは何も表示されません。私は何かを紛失していますか、またはgccが不適合ですか?

答えて

0

生成されたマシンコードが無条件で両方のポインタに書き込みます

do_test: 
     cmpl $1, %edx 
     movl $0x4e931ab1, (%rsi) 
     sbbl %eax, %eax 
     andl $-567890, %eax 
     addl $1234567890, %eax 
     movl %eax, (%rdi) 
     ret 

すべての店舗がchange the dynamic type of the memory accessedに期待されているので、これはGCCのバグです。私はこの行動が標準によって義務づけられているとは思わない。それはGCC拡張です。

GCCのバグを報告できますか?

+1

リンクされたポストを読むと、宣言された型*を持つストアド・オブジェクトの動的な型をストアが変更することは拡張であることが示唆されていますが、そのような振る舞いは宣言された型のないオブジェクト'malloc()'から受け取ったポインタ)。標準を守るためには、コンパイラが不必要に効率の悪いコードを生じることが多い場合には、ある種の悲観的な仮定を必要とし、コンパイラがオブジェクトの動的/有効な値を許さない*不適合モードを提供することは意味があるそのような場合に変更するタイプ。 – supercat

+0

それ以外の場合、gccのバグを登録するのは現在登録されていませんが、登録する必要があります。しかし、行動が適合していると説明できる方法がない場合、救済策として提案されるべきものは何かを確かめることはできません。規格を守ることは、場合によっては最適化を不必要に妨げることを考えると、 '-fno-strict-aliasing'が完全な適合のために必要であり、' -fstrict-aliasing'が決して決して使用できないコードストレージをリサイクルします。残念なことに、これは、ストレージをリサイクルする必要があるコードが非効率的に処理されることを意味します。 – supercat

0

はい、これはgccのバグです。私はそれをhttps://gcc.gnu.org/bugzilla/show_bug.cgi?id=82697として(単純化されたテストケースで)提出しました。

+0

このバグを投稿していただきありがとうございます。興味深いことに、この店舗発注のバグは、このような迅速な修正をもたらしたようですが、82697は時間がかかりそうです。私は、標準の作成者が、* piと* plが*かもしれないことを示唆する証拠がない場合でもエイリアス*を認識するために必要な苦情を要求することを意図していたことは知らないが、確かにその可能性を認識することは、不合理な悲観的なものではなく、単に現実的なものであることを認識しています(上記の例では、ポインタキャストと同様に)。 – supercat

関連する問題