2014-04-28 77 views
1

我碰到這個簡單的程序就某處使用的#define定義結構對象

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

char buffer[2]; 
struct globals { 

    int value; 
    char type; 
    long tup; 

}; 

#define G (*(struct globals*)&buffer) 

int main() 
{ 
     G.value = 233; 
     G.type = '*'; 
     G.tup = 1234123; 

     printf("\nValue = %d\n",G.value); 
     printf("\ntype = %c\n",G.type); 
     printf("\ntup = %ld\n",G.tup); 

     return 0; 
} 

它編譯(使用gcc)和執行很好,我得到下面的輸出:

Value = 233 
type = * 
tup = 1234123 

我不是確定#define G語句的工作方式。 G是如何定義爲struct globals類型的對象的?

+2

你'buffer'太小,它的長度應該至少'的sizeof(結構全局)'。 –

+0

@ user28264提供了一個寫得很好並且詳盡的答案。如果它回答了你的問題或給出了關於問題的更多信息/告訴它爲什麼不夠,你應該將其標記爲接受。否則,由於沒有接受答案,它將保持未答覆狀態。 –

回答

1

該宏只是將2個字符的緩衝區地址轉換爲指向適當結構類型的指針,然後將其解除引用以產生一個結構類型的左值。這就是爲什麼點(.)結構訪問操作符在G上工作的原因。

不知道爲什麼有人會這樣做。我認爲當需要(在示例代碼中「從不」),或者使用union獲得更大的原始代碼庫中的某個地方時,它可以更清晰地轉換爲字符數組中的字符數組擺脫宏觀。

union { 
    struct { 
    int value; 
    /* ... */ 
    } s; 
    char c[2]; 
} G; 

G.s.value = 233; /* and so on */ 

既清潔又清晰。請注意,char陣列太小。

4

首先,此代碼具有未定義的行爲,因爲它將一個雙字節數組重新解釋爲更大的struct。因此,它正在寫入已分配空間的末尾。你可以讓你的程序有效利用struct的大小申報buffer陣列,像這樣:

struct globals { 
    int value; 
    char type; 
    long tup;  
}; 
char buffer[sizeof(struct globals)]; 

#define工作中的慣常方式 - 通過提供令牌G的文本替換,因爲如果你在你最喜歡的文本編輯器中運行搜索和替換。預處理器,C編譯器的第一階段,找到每個條目G,並用(*(struct globals*)&buffer)替換它。

一旦預處理完成後,編譯器看到這個代碼:

int main() 
{ 
    (*(struct globals*)&buffer).value = 233; 
    (*(struct globals*)&buffer).type = '*'; 
    (*(struct globals*)&buffer).tup = 1234123; 

    printf("\nValue = %d\n",(*(struct globals*)&buffer).value); 
    printf("\ntype = %c\n",(*(struct globals*)&buffer).type); 
    printf("\ntup = %ld\n",(*(struct globals*)&buffer).tup); 

    return 0; 
}