簡體   English   中英

什么是預處理器宏有用?

[英]What are preprocessor macros good for?

閱讀另一個問題關於使用宏后,我在想: 它們是什么好?

我很快就會看到被其他語言構造取代的一件事是減少你需要在下面輸入的相關單詞的數量:

void log_type( const bool value ) { std::cout << "bool: " << value; }
void log_type( const int value ) { std::cout << "int: " << value; }
...
void log_type( const char  value ) { std::cout << "char: "  << value; }
void log_type( const double  value ) { std::cout << "int: "  << value; }
void log_type( const float  value ) { std::cout << "float: "  << value; }

而不是

#define LOGFN( T ) void log_type( const T value ) { std::cout << #T ## ": " << value; }
LOGFN( int )
LOGFN( bool )
...
LOGFN( char )
LOGFN( double )
LOGFN( float )

還有其他“不可替代的”嗎?

編輯:試圖總結原因 - 為什么在答案中遇到; 因為那是我感興趣的東西。主要是因為我有一種感覺,他們中的大部分是由於我們仍然在原始文本文件中編程,仍然是支持不佳的環境。

  • 代碼編譯的靈活性(例如#ifdef DEBUG ,平台問題)(SadSido,Catalin,Goz)
  • 調試目的(例如__LINE__, __TIME__ ); 我也根據這個原因設置'字符串'(SadSido,Jla3ep,Jason S)
  • 替換例如PHP的requireinclude功能( #pragma once )(SadSido,Catalin)
  • 通過替換復雜的代碼來增強可讀性(例如MESSAGEMAPBOOST_FOREACH )(SadSido,fnieto)
  • 干原則(傑森S)
  • 內聯替換(Matthias Wandel,Robert S. Barnes)
  • stringifying(傑森S)
  • 在不同的條件下編譯不同的代碼( #ifdef __DEBUG__ );
  • 保護每個翻譯單元包含一次標題( #pragma once );
  • __FILE____LINE__ - 由當前文件名和當前行替換;
  • 構造代碼以使其更具可讀性(例如: BEGIN_MESSAGE_MAP() );

在這里看到有趣的宏觀討論:

http://www.gotw.ca/gotw/032.htm

http://www.gotw.ca/gotw/077.htm

最有用的 - 頭文件保護:

#ifndef MY_HEADER_GUARD
#define MY_HEADER_GUARD

// Header file content.

#endif 

稍后添加[ 僅限Windows ]

將類導出到DLL:

#ifdef EXPORT_MY_LIB
#define    MY_API __declspec( dllexport)
#else
#define    MY_API __declspec( dllimport)
#endif

樣本類:

class MY_API MyClass { ... };

平台特定部分。

#ifdef WINDOWS
#include "WindowsImplementation.h"
#elif defined( LINUX )
#include "LinuxImplementation.h"
#else
#error Platform undefined.
#endif

我以前發過這個,但當然現在找不到了。 如果你想訪問__FILE____LINE__宏,那么另一個宏是目前最方便的方式 - 例如:

#define ATHROW(msg)                                         \
{                                                           \
    std::ostringstream os;                                  \
    os << msg;                                              \
    throw ALib::Exception( os.str(), __LINE__, __FILE__ );  \
}

為了做一些像BOOST_FOREACH這樣的酷魔術技巧, 將變量注入一個范圍。

BOOST_FOREACH( char c, "Hello, world!" )
{
   ... use char variable c here ...
}   // c's scope ends here
// if there's an outer c defined, its scope resumes here

因為不重復自己(DRY)的原因。 在編譯時涉及重復構造的事情,不能在其他方法(模板或你有什么)中抽象出來。 如果您發現重復相同的代碼構造20次,那么這是人為錯誤的潛在根源 - 希望可以使用模板將其抽象出去,但有時卻不會。 它總是在看到可以進行類型檢查和清晰審查的原始代碼的優勢與使用宏來實現任意替換模式(通常無法通過自動編程工具檢查)的優勢之間取得平衡。

字符串化和連接(#和##預處理器模式)不能由模板執行。

當然,在某些時候,您可能最好使用工具(無論是自定義還是現成的)來自動生成代碼。

現代語言采用的理念是需要一個支持處理器的語言功能缺失的標志,因此它們定義了預處理器在舊的K&R風格C中非常簡單地處理的各種語言功能。

例如,上面的代碼示例可以通過內聯函數進行簡化。

就個人而言,預處理器中最不可或缺的方面是清楚地表明某些事情是在源代碼中編譯完成的。 在編譯時消除死代碼路徑的java方法在讀取代碼時並不那么明顯。

他們的一個用途基本上是一個窮人(內聯)模板功能。

例如

#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y))

這允許您為支持這些運算符的任何類型生成自定義MIN函數,這些函數在使用時實際上是內聯的。 當然沒有類型檢查,如果你沒有恰到好處的話,很容易就會出現奇怪的語法錯誤或不正確的行為。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM