幾個難懂的 C 語言宏[還是沒搞清楚]

來源:互聯網
上載者:User

幾個難懂的 C 語言宏[還是沒搞清楚]

 

可變參數宏

有些時候定義一個宏來代替某個函數 但是這個函數是可變參數的話 那就需要考慮辦法了

定義方法如下

CODE

#define PRINT(...) printf(__VA_ARGS__)
#include <stdio.h>
int main(){
PRINT("%d %s %s",1,"吃飯了嗎 smile MM:)","\n");
return 0;
}

 

宏組合

也就是## 和 #的用法
## 是串連符號 串連兩個宏
#是把名字代替成字串

如下

CODE

#define s5(a) supper_ ## a
#include <stdio.h>
void supper_printf(const char* p )
{
printf("this is supper printf:\n%s\n",a);
}

int main()
{
 s5(printf)("hello owrld");
 return 0;
}

#用法如下
#include <stdio.h>
#define s(p) #p
int main(){
printf(s(p)"\n");
return 0;
}

運行一下就知道了
--------------------------------------------------

#pragma once

#ifndef _MALLOC_SAFE_H_
#define _MALLOC_SAFE_H_

#include <stdio.h>
#include <string>

//#define malloc3(size) ( malloc_fast_safe(size, __FILE__, __FUNCTION__, # __LINE__) )
#define malloc(size) ( malloc2(size, __LINE__) )
#define malloc_line(size, line) ( malloc_fast_safe(size, __FILE__, __FUNCTION__, #line) )
#define free(buf) ( free_fast_safe(buf) )

//一個簡單的快速檢測方式
void * malloc_fast_safe(int len, const char * c__FILE__, const char * c__FUNCTION__, const char * c__LINE__);

void free_fast_safe(void * p);

#endif
--------------------------------------------------

還是不行,要這樣

#pragma once

#ifndef _MALLOC_SAFE_H_
#define _MALLOC_SAFE_H_

#include <stdio.h>
#include <string>

//宏裡面轉換成字串還是很囉嗦,要用兩級宏加 "#" 來處理
#define __STRINGIFY__(x) #x
#define __TOSTRING__(x) __STRINGIFY__(x)

//#define malloc(size) ( malloc_fast_safe(size, __FILE__, __FUNCTION__, #__LINE__) )
#define malloc(size) ( malloc_fast_safe(size, __FILE__, __FUNCTION__, __TOSTRING__(__LINE__)) )
#define free(buf) ( free_fast_safe(buf) )

//一個簡單的快速檢測方式
void * malloc_fast_safe(int len, const char * c__FILE__, const char * c__FUNCTION__, const char * c__LINE__);

void free_fast_safe(void * p);

#endif

參考自 google "__LINE__ 字串"

http://www.cppblog.com/heath/archive/2008/08/05/58046.html

--------------------------------------------------

使用__FILE__和__LINE__定位錯誤

[前言:使用__FILE__和__LINE__來定位錯誤已經屢見不鮮,然而其中一些道理又有幾個人仔細探究過。本文參考了Curtis Krauskopf的一篇名為Using __FILE__ and __LINE__ to Report Errors的文章,希望達到解惑之效。]

問題:當執行階段錯誤產生時,我怎樣才能得到包含C++檔案名稱和行號的字串資訊?
回答:在C++中的__FILE__先行編譯指標包含了被編譯的檔案名稱,而__LINE__則包含了原始碼的行號。__FILE__和__LINE__的前後都包含了兩個底線,讓我們仔細看看__FILE__所包含的每個字元:

_ _ F I L E _ _

下面展示了在控制台程式中如果顯示檔案名稱和程式碼號。

#include <stdio.h>

int main(int , char**)
{
     printf("This fake error is in %s on line %d\n",         __FILE__, __LINE__);
     return 0;
}

輸出結果:

This fake error is in c:\temp\test.cpp on line 5

讓我們更上一層樓

我想通過一個通用函數error()來報告錯誤,以使當某個錯誤發生時我能設定斷點以及隔離錯誤處理(例如,在螢幕上列印錯誤資訊或者寫入日誌)。因此,函數的原型應該是這樣的吧:

void error(const char *file, const unsigned long line, const char *msg); 

調用方式如下:

error(__FILE__, __LINE__, "my error message");

預先處理魔法

這裡有三個問題需要解決:

  1. __FILE__和__LINE__在每次調用error時作為參數傳入。
  2. __FILE和__LINE__前後的底線很容易被遺忘,從而導致編譯錯誤。
  3. __LINE__是一個整數,這無疑增加了error函數的複雜度。我絕不想直接使用整型的__LINE__,而通常都是將轉換為字串列印到螢幕或寫入記錄檔。

__FILE__和__LINE__應該被自動處理,而非每次作為參數傳遞給error,這樣會讓error的使用者感覺更爽些,它的形式可能是下面這樣:

error(AT, "my error message");

 
我希望上面的宏AT展開為:"c:\temp\test.cpp:5"。而新的error函數則變成:

void error(const char *location, const char *msg);

 

因為Borland C++ Builder編譯器能夠自動合并相鄰的字串,因此我把AT寫成下面這樣:

#define AT __FILE__ ":" __LINE__ 

然而它卻罷工了,因為__LINE__被擴充成了整數而非字串,所以宏展開後變成:

"c:\temp\test.cpp" ":" 5

這是一個無效的字串,因為末尾有一個未被雙引號包含的整數。

怎麼辦?別著急,一個特殊的先行編譯指標“#”能夠幫我們將一個變數轉換成字串。所以重新定義宏:

#define AT __FILE__ ":" #__LINE__
嘿嘿,這樣總行了吧。別高興得太早,這樣也是不行的。因為編譯器會抱怨#是個無效字元。其實,問題是#先行編譯指標只有這樣使用才會
被正確識別:
#define symbol(X) #X 

因此,我把代碼改為:

#define STRINGIFY(x) #x
#define AT __FILE__ ":" STRINGIFY(__LINE__) 

然而,奇怪的結果產生了,__LINE__居然被作為了輸出的一部分:

c:\temp\test.cpp:__LINE__: fake error

解決方案是再用一個宏來封裝STRINGIFY():

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)

OK,我們用下面的代碼來試試:

#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)
void error(const char *location, const char *msg)
{
  printf("Error at %s: %s\n", location, msg);
}
int main(int , char**)
{
  error(AT, "fake error");
  return 0;
}

輸出結果:

Error at c:\temp\test\test.cpp:11: fake error

Visual Studio下的實踐
在《Windows核心編程》中,Jeffrey Richter提供了下面的宏在編譯期輸出有用資訊:

#define chSTR2(x) #x
#define chSTR(x)  chSTR2(x)
#define chMSG(desc) message(__FILE__ "(" chSTR(__LINE__) "):" #desc)

message是一個先行編譯指令,上面宏的使用方法是:

#pragma chMSG(Fix this later)

結論

  1. 先行編譯指標__FILE__和__LINE__能夠提供有用的資訊。
  2. __LINE__的處理方式遠比我們想象的要複雜。
  3. __FILE__被處理成字串,給我們帶來了不少方便。

posted on 2008-08-05 11:55

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.