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が不適合ですか?
リンクされたポストを読むと、宣言された型*を持つストアド・オブジェクトの動的な型をストアが変更することは拡張であることが示唆されていますが、そのような振る舞いは宣言された型のないオブジェクト'malloc()'から受け取ったポインタ)。標準を守るためには、コンパイラが不必要に効率の悪いコードを生じることが多い場合には、ある種の悲観的な仮定を必要とし、コンパイラがオブジェクトの動的/有効な値を許さない*不適合モードを提供することは意味があるそのような場合に変更するタイプ。 – supercat
それ以外の場合、gccのバグを登録するのは現在登録されていませんが、登録する必要があります。しかし、行動が適合していると説明できる方法がない場合、救済策として提案されるべきものは何かを確かめることはできません。規格を守ることは、場合によっては最適化を不必要に妨げることを考えると、 '-fno-strict-aliasing'が完全な適合のために必要であり、' -fstrict-aliasing'が決して決して使用できないコードストレージをリサイクルします。残念なことに、これは、ストレージをリサイクルする必要があるコードが非効率的に処理されることを意味します。 – supercat