[英]macro and function conflict in C
當C中的宏和函數沖突出現時會引發什么錯誤? 是宏處理器錯誤還是由於某些語言違規而發生此錯誤?
例如,在此代碼中:
#include <stdio.h>
#define MAX(i, j) (i>j)? i : j
int MAX(int i, int j){
return (i>j) ? i : j;
}
int main(){
int max = MAX(5, 7);
printf("%d",max);
return 0;
}
該程序拋出編譯時錯誤。 但我不明白它是否是某種語言違規或宏擴展錯誤或其他原因。
在預處理階段,代碼轉換為:
int (int i>int j)? int i : int j{
return (i>j) ? i : j;
}
int main(){
int max = (5>7)? 5 : 7;
printf("%d",max);
return 0;
}
...正如任何人都知道的那樣,是非法的C代碼。
(使用gcc
您可以使用-E
選項查看文件的預處理版本。)
其他人指出了問題,但沒有給出任何解決方案。 最好的方法是使用MAX作為內聯函數。 如果宏位於標題中,請將內聯函數定義放在標題中。 如果您仍希望使用宏(或使用不支持內聯函數的舊C編譯器),則可以通過以下方式定義函數:
int (MAX)(int i, int j){
return (i>j) ? i : j;
}
這將防止令人不安的宏擴展並提供MAX作為外部功能。 例如,這將使您能夠將其地址分配給變量。
extern int (MAX)(int, int);
...
int (*max_func_ptr)(int, int);
...
max_func_ptr = MAX;
您將收到編譯器錯誤,因為在嘗試編譯之前將擴展宏。
這是一個非常討厭的問題,並且沒有真正的解決方案。 因此,您應該盡可能避免定義無范圍的,類似函數的宏,尤其是在廣泛包含的標頭中。 像所有東西一樣,它們都有它們的位置,但你需要注意不要過度使用它們。
沒有任何錯誤特別發生,以確定存在沖突。 會發生什么是宏處理首先發生,所以在某種意義上宏定義不尊重名稱空間 - 這是宏被認為是壞形式的主要原因之一,應該避免,除非作為最后的手段。 請參閱此問題,以獲取一個例子,其中某人完全有效地使用名稱BitTest
作為模板被搞砸了,因為其他人決定使用該名稱創建一個宏來“別名”另一個名稱: Win32:BitTest,BitTestAndComplement,.. 。< - 如何禁用這個垃圾?
因此,在您的示例中,正如其他答案所提到的,一旦預處理步驟發生,您將最終得到類似下面的代碼段傳遞給C編譯器代替您的函數定義:
int (int i>int j)? int i : int j{
return (i>j) ? i : j;
}
這不是有效的C,因此您可能會遇到編譯器錯誤(來自GCC 3.4.5):
error: syntax error before "int"
或(來自MSVC 9):
error C2059: syntax error : 'type'
這真的沒什么幫助,因為當你看到錯誤在你的編輯器中引用的那一行時,它仍然看起來像:
int MAX(int i, int j){
看起來有效。
有幾種技術可用於幫助避免此問題:
對宏名稱和宏名稱使用全部大寫; 這是一個大致遵循的約定,以使宏命名空間與用於其他事物的名稱分開
將parens放在你不希望擴展為宏的名稱周圍(這僅適用於'類似函數'的宏)。 如果您的示例編寫如下:
int (MAX)(int i, int j){ return (i>j) ? i : j; }
它不會導致宏觀擴張。 但是,我不認為人們經常這樣做。 我使用的一組實用程序例程使用這種技術來防止宏命名沖突,我經常會問到為什么所有的函數名都在parens中。 此外,一些編輯也對這些文件的功能導航感到困惑。
避免使用宏; 正如我所提到的,這是宏被認為是壞形式的一個原因。 還有其他原因包括如果您沒有在宏參數周圍正確使用parens或者通過評估具有多次副作用的宏參數,它們很容易導致擴展形式產生錯誤或意外的表達式。
如果可以,請使用內聯函數或函數模板。
由於預處理器宏僅用於處理純文本,因此這些沖突總是會導致編譯時錯誤。
預處理首先發生,因此第4行將變為:
int (int i>int j)? int i : int j
這是無效的C.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.