2016-11-24 99 views
0

在ISO/IEC 9899:1999的第6.7.7節中類型定義,第三個示例(在邊界上標記的第6段)不正確。從該示例中的解釋是這樣(參見底部的代碼):沒有類型說明符的類型限定符

前兩個比特的字段聲明在無符號的不同是 類型說明符(這迫使t是一個結構部件的名稱), 而const是類型限定符其改變t是 作爲typedef名稱)仍然可見。

它聲明const t:5將使類型名稱t的先前定義保持不變。如果我們使用gcc進行測試,我們發現我們可以改變這個變量,所以gcc忽略了const t。用clang編譯也是一樣。

我明白,這是有可能存在的變量定義/通過類型修飾符沒有類型說明符,這違背了我的信念,即預選賽只有保持一個類型說明符節點的屬性等

聲明C99的歧義在哪裏?

typedef signed int t; 
typedef int plain; 
struct tag { 
    unsigned t:4; 
    const t:5; 
    plain r:5; 
}; 

int 
main() 
{ 
    t x; 
    x = 10; 
    return 0; 
} 

在另一方面,像下一個函數也是編譯:

int 
main() 
{ 
    struct tag x = {.t = 3}; 
    x.t = 4; 
    return 0; 
} 

REMARK

我用鐺和gcc。

DOCUMENTS

頁138,§6.7.8從這個版本

ISO/IEC 9899:201X委員會草案 - 2011年4月12日N1570

OR

第124頁,第6.7節。TC3委員會草案 - 2007年9月7日WG14/N1256

+0

它不是重新定義的類型定義,它的修改類型用於在您添加了預選賽的具體變量。 – Barmar

+0

看來,.t可以修改,看到更新的功能。 – alinsoar

回答

0

完整的高談闊論的例子(從ISO/IEC 9899:2011)從這個版本

ISO/IEC 9899 7:

實例3將下列晦澀構造

typedef signed int t; 
typedef int plain; 
struct tag { 
    unsigned t:4; 
    const t:5; 
    plain r:5; 
}; 

聲明typedef名tsigned int類型,typedef名稱plain與類型和一個結構爲 ,其中包含三個位域成員,一個名爲t,其中包含值範圍[0,15],一個未命名的常量合格的 位字段(如果可以訪問的話)將包含範圍[-15,+15]或 [-16,+15],以及一個名爲r的值,其中包含範圍[0,31],[-15,+15]或[-16, +15。 (範圍的選擇是實現定義的。)前兩個位域聲明的區別在於 unsigned是一個類型說明符(它強制t成爲結構成員的名稱),而const是 類型限定符(它修改了t,它仍然作爲typedef名稱可見)。如果這些聲明由

t f(t (t)); 
long t; 

然後在內部範圍隨後 函數f與類型「」函數與一個未命名參數 返回signed int型指針聲明爲函數返回signed int與一個未命名的參數與signed int型'',標識爲t,類型爲long int

注意,通過const t:5;認定的領域是匿名的,因此不能被訪問(標準提到,隨着「如果它可以訪問」評論,聲明它是一個「無名const限定比特領域')。名爲t的字段不是const限定的;它可以被修改。

const字段是結構struct tag的一部分,並且不影響該結構類型之外的任何內容。

這兩個示例程序都應該編譯 - GCC和Clang編譯它們也是一樣。

也請注意,該例子被標記爲「晦澀結構」。任何人爲了生產而編寫這樣的代碼都應該......避開,直到他們悔改自己的惡行。

+0

現在我明白了。事實上它是有效的。因爲在第一種情況下'無符號T:4'類型說明符爲'unsigned'和't'是在結構的成員的命名空間中的ID,而在第二情況下,t是一個類型名稱中的標識符的名稱空間,所以他們是不同池中的實體,不要互相沖突。另一方面,''const t:4''作爲一個未命名的字段是有效的,因爲類型名稱't'是一個整數。好。現在很明顯。 – alinsoar

+0

是的;這是正確的分析。這是一個標準,說明一些規則是如何令人難以忍受的。 –

+0

簡而言之,它是一個類型限定符,與一個類型名稱,而不是在混淆的上下文中的類型說明符。 – alinsoar