簡體   English   中英

使用C宏創建映射到Objective-C消息調用的C風格代碼?

[英]Using C macros to create C-style code which maps to Objective-C message calls?

我相信我會得到20個人說“你為什么要這樣做呢”......但是,我會問我的問題,因為它有點學術性質。

我想使用C宏將[ClassName new]重新定義為: new(ClassName) ,我想知道如何做到這一點。 我對C宏開始並不是很滿意(我知道 - 令人尷尬 - 我應該這樣) - 我絕對不喜歡將它們與我的Objective-C代碼混合使用。 那么,關於這個問題......

首先,作為預處理器,我可以做一個簡單的替換:

#define new(x) [x new]

或者,無論出於何種原因,我是否需要下載到objective-c運行時,並執行更類似於以下的操作:

#define new(x) objc_msgSend(class_createInstance(x, 0), sel_registerName("init"))

做這樣的事情會有什么不足之處?

這種事情經常被其他人使用,或者,有人會看着它說“你在那里做什么”? (我應該關心)

謝謝

編輯:

事實上,在我發布之后,我發現事實上,我之前看到過這種事情 - 在Three20 lib中,他們做了這樣的事情:

#define TT_RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; }
#define TT_INVALIDATE_TIMER(__TIMER) { [__TIMER invalidate]; __TIMER = nil; }

// Release a CoreFoundation object safely.
#define TT_RELEASE_CF_SAFELY(__REF) { if (nil != (__REF)) { CFRelease(__REF); __REF = nil; } }

所以我的問題可能很簡單; 這樣做有什么不足之處,這是一種相對公認的做法,還是會讓我陷入更多困境的事情呢?

C宏是有保證的

  • 不要遞歸
  • 不擴展未遵循的功能宏()

所以你的第一個變體對於C預處理器來說是可以的。 保留的唯一標識符(因此您不能用於宏名稱)是以下划線開頭的關鍵字和標識符。 new既不是關鍵字(對於C)也不是以下划線開頭,所以這對C預處理器來說很好。

我不知道目標-C是否會施加其他限制,你必須要查看它。

是的,我絕對是那個問“為什么你還想這樣做呢?”的人。 不要這樣做,甚至不要這樣做,如果另一方面你覺得有必要問你的問題。

首先處理宏,並且它們在純文本源代碼上運行。 所以,是的,如果您願意,可以讓您的new宏生成Objective-C語法或純C語法甚至無效語法。

一般使用宏的缺點是,因為它是在單獨的步驟中解析和處理的,所以即使一切看起來都很好,也可以編寫不符合預期的宏。

例如,這個宏:

#define MAX(x,y) x > y ? x : y

看起來不錯,但是你說你像這樣使用它:

z = MAX(a,MAX(b,c));

它將由預處理器擴展為如下所示:

z = a > b > c ? b : c ? a : b > c ? b : c;

哪個實際上不會給你三個參數的最大值。 要解決這個問題,您需要在宏定義中自由地使用括號,即使您不認為需要它也是如此:

#define MAX(x,y) ((x) > (y) ? (x) : (y));

這修復了它,除了我添加了一個分號到最后,這是一個可以理解的習慣,編寫了很多C代碼,除了現在我們的宏擴展到:

z = ((a) > (((b) > (c) ? (b) : (c));) ? (a) : (((b) > (c) ? (b) : (c));));;

語法錯誤!

如果你看一下在Objective-C中實際定義的MAX是多么糟糕,但這就是你必須要做的安全編寫宏。 而你還需要考慮:

z = MAX(expensiveComputation(), reallyExpensiveComputation())

與函數不同,它實際上會執行兩次這樣的函數之一,除非你在宏中使用一個技巧來基本上模擬參數傳遞。

所以,回答你的問題,是的,它完全有可能,但編寫安全的宏真的很難。 而你正在這樣做,所以你可以假裝你的Objective-C代碼實際上是另一種語言的代碼......為什么你想這樣做,反正呢?

假設您使用的是最近的GCC(即4.6版本),您可以考慮為此類任務制作GCC 插件 ,或者最好是GCC MELT 擴展 MELT是一種高級域特定語言,可以輕松擴展GCC。

例如,你的new宏將是

#define new(X) _mybuiltin_new_(X)

然后你的MELT擴展將添加一個新的GCC內置_mybuiltin_new_ ,它將被轉換為一些更簡單的Gimple(GCC使用的內部表示)。 然而,這些事情需要一些時間(至少一周,而不是幾小時)來開發。

暫無
暫無

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

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