2017-10-05 92 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; 
} 

從我的標準的閱讀,在註釋中描述的功能的所有三個用途應嚴格符合(除整數範圍的問題)。代碼應該輸出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 

這是一個錯誤的GCC,因爲所有的商店都有望change the dynamic type of the memory accessed。我不認爲這種行爲是由標準強制的;這是一個GCC擴展。

你能提交一個GCC錯誤嗎?

+1

我對鏈接文章的閱讀表明,商店使用聲明類型更改對象的動態類型*是擴展,但標準對於沒有聲明類型的對象需要此類行爲[例如,從'malloc()']收到的指針。維護標準將要求編譯器在通常會產生不必要的低效代碼的情況下做出某些悲觀的假設,編譯器提供*不一致*模式是有意義的,這種模式不會對對象的動態/有效在這種情況下要更改的類型。 – supercat

+0

否則,我目前沒有註冊gcc bug,儘管也許我應該註冊。但我不確定,如果沒有辦法將行爲描述爲符合,應該提出什麼樣的補救措施。鑑於在某些情況下支持標準會不必要地阻礙優化,因此可以簡單地說完全一致性需要'-fno-strict-aliasing'並指定'-fstrict-aliasing'只能用於永不代碼的代碼回收存儲。不幸的是,那意味着任何需要回收存儲的代碼都會被低效處理。 – supercat

0

是的,這是一個海灣合作委員會的錯誤。我用https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82697提交了它(帶有簡化的測試用例)。

+0

感謝您發佈該錯誤。有趣的是,這家商店訂購錯誤似乎已經取得了如此快速的解決,但82697似乎需要更長的時間。我不知道標準的作者是否打算要求認識到'* pi'和'* pl'可能會混淆*,即使沒有證據表明他們可能會*,但當然有證據(如同上面例子中的指針一樣),認識到這種可能性並不是不合理的悲觀,而僅僅是現實的。 – supercat

相關問題