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;
}
從我的標準的閱讀,在註釋中描述的功能的所有三個用途應嚴格符合(除整數範圍的問題)。代碼應該輸出1234567890 1234000000.00
。但是,GCC 7.2輸出1234056789 1157904.00
。我認爲當leave_as_int
爲0時,它將123400000.0f存儲到*p2
後存儲123400000到*p1
,但我在標準中沒有看到任何可授權此類行爲的內容。我錯過了什麼,或者是gcc不符合?
我對鏈接文章的閱讀表明,商店使用聲明類型更改對象的動態類型*是擴展,但標準對於沒有聲明類型的對象需要此類行爲[例如,從'malloc()']收到的指針。維護標準將要求編譯器在通常會產生不必要的低效代碼的情況下做出某些悲觀的假設,編譯器提供*不一致*模式是有意義的,這種模式不會對對象的動態/有效在這種情況下要更改的類型。 – supercat
否則,我目前沒有註冊gcc bug,儘管也許我應該註冊。但我不確定,如果沒有辦法將行爲描述爲符合,應該提出什麼樣的補救措施。鑑於在某些情況下支持標準會不必要地阻礙優化,因此可以簡單地說完全一致性需要'-fno-strict-aliasing'並指定'-fstrict-aliasing'只能用於永不代碼的代碼回收存儲。不幸的是,那意味着任何需要回收存儲的代碼都會被低效處理。 – supercat