2011-01-30 76 views
2

亞當柯提供了一個宏偉的解決了這個問題,謝謝亞當柯。如果像我一樣,你喜歡c預處理器(處理#defines的東西),你可能並不知道XCode中有一個方便的東西:右鍵單擊你的一個開源文件的主體,靠近底部去.. 「預處理」。它實際上運行預處理器,向您展示將要編譯的內容的「真實交易」。這很棒!將「forCount」控件結構添加到Objective-C的最佳方法是什麼?


這個問題是一個風格和代碼清晰的問題。考慮它類似於約微妙的命名問題,或可用成語中的最佳選擇(可讀性更強,更易於維護)問題。

當然的事,一個使用循環是這樣的:

for(NSUInteger _i=0; _i<20; ++_i) 
    { 
    .. do this 20 times .. 
    } 

需要明確的是,效果是做一些N倍。 (你是在體內使用索引。)

我想對讀者,這是一個基於計數的循環明確信號 - 即,指數是無關緊要的,算法,我們正在做的事情N次。

因此,我希望有一個乾淨的方式做一個身體N次,沒有皇帝的糾葛或浪漫的承諾。你可以這樣做一個宏:

#define forCount(N) for(NSUinteger __neverused=0; __neverused<N; ++__neverused) 

和那個作品。因此,

forCount(20) 
    { 
    .. do this 20 times .. 
    } 

但是,可以想象的「隱藏」的變量中使用有可能引起麻煩,如果它在未來的某事發生碰撞。 (或許,如果你嵌套有問題的控制結構,其他方面的問題。)

需要明確的是效率,等等,是不是這裏的問題。已經有幾個不同的控制結構(同時,做,等等等等),這實際上是當然完全一樣的東西,但它存在只是作爲風格問題,並清楚地表明讀者預期的算法意義的代碼段的問題。 「forCount」是另一種需要的控制結構,因爲「索引無關」計數循環在任何算法編程中都是完全基本的。

有誰知道真的,真的,真的很酷的解決方案呢?上面提到的#define並不令人滿意,而且你已經輸入了一個不可避免的變量名稱。

謝謝!


後...

一對夫婦的人都基本上是問:「爲什麼要那樣做?「

請看下面的兩個代碼示例:

for (spaceship = 3; spaceship < 8; ++spaceship) 
    { 
    beginWarpEffectForShip(spaceship) 
    } 

forCount(25) 
    { 
    addARandomComet 
    } 

效果當然是完全,並顯着爲讀者不同

畢竟,有alresdy衆多(完全相同)的控制結構在c中,唯一不同的是風格:也就是說,將內容傳遞給閱讀器

每次我們觸摸鍵盤時,我們都使用「非索引相對」循環(「做某事5次」) ,它像餡餅一樣自然。

所以,#define是一個好的解決方案,有沒有更好的方法來做到這一點?乾杯

+0

可不可以給我的時候,你只需要做些什麼了N次了幾個例子,沒有使用循環內的任何東西的索引? – 2011-01-30 16:41:12

+0

'#define`將*仍*創建你永遠不會使用的索引變量。所有的編譯器確實是用你的forCount()宏代替實際的for()結構。這就是爲什麼你提到的嵌套問題存在。 – BoltClock 2011-01-30 16:41:20

+0

你想在這裏解決什麼問題?爲什麼正常的循環不適合?沒有人強迫你使用索引變量,如果你不想... – 2011-01-30 16:45:29

回答

4

更好的方法是這樣做是爲了讓嵌套forCount結構 -

#define $_TOKENPASTE(x,y) x##y 
#define $$TOKENPASTE(x,y) $_TOKENPASTE(x, y) 

#define $itr   $$TOKENPASTE($_itr_,__LINE__) 
#define forCount(N) for (NSUInteger $itr=0; $itr<N; ++$itr) 

然後你可以使用它像這樣

forCount(5) 
{ 
    forCount(10) 
    { 
     printf("Hello, World!\n"); 
    } 
} 

編輯: 您在您的評論提出的問題可以很容易地修復。簡單地改變上面的宏成爲

#define $_TOKENPASTE(x,y) x##y 
#define $$TOKENPASTE(x,y) $_TOKENPASTE(x, y) 

#define UVAR(var)   $$TOKENPASTE(var,__LINE__) 
#define forCount(N)   for (NSUInteger UVAR($itr)=0, UVAR($max)=(NSUInteger)(N); \ 
           UVAR($itr)<UVAR($max); ++UVAR($itr)) 

它所做的是它讀取你的forCount參數給出表達式的值,並使用值進行迭代,這樣你避免多次評估。

1

不,沒有冷卻器解決方案(不是蘋果公司的GCC版本)。 C工作的級別要求您明確地爲需要計數的每個任務設置計數器,而且該語言無法創建新的控制結構。

其他編譯器/版本的GCC有一個__COUNTER__宏,我認爲它可以以某種方式與預處理器粘貼一起使用來創建唯一標識符,但我無法想象使用它來以有用的方式聲明標識符的方法。

關於在for中聲明一個變量並從未在其身體中使用它,有什麼不清楚的地方?

+1

+1確切地說,它不像編譯器會對計數器變量產生任何噪音,無論如何是「未使用」的。 – BoltClock 2011-01-30 16:39:49

2

說實話,我認爲你已經解決了一個非問題。

如果想遍歷整個集合,使用Objective-C 2樣式迭代器,如果您只想迭代有限次數,則只需使用標準for循環 - 從未使用的內存空間釋放整數是毫無意義的。

包裝這些標準方法只是覺得不必要和違反直覺。

+2

你如何**超過**解決非問題? :P – BoltClock 2011-01-30 16:41:56

-1

爲什麼不把宏中的變量的名稱?事情是這樣的:

#define forCount(N, name) for(NSUInteger name; name < N; name++) 

然後,如果你想你的嵌套控制結構:

forCount(20, i) { 
    // Do some work. 
    forCount(100, j) { 
     // Do more work. 
    } 
} 
+1

然後它變成了一種保存擊鍵的方法。完全擊敗目的。 – BoltClock 2011-01-30 16:48:51

+1

一些深奧的`#define`宏如何被清除給讀者而不是深思熟慮的評論? – 2011-01-30 16:59:56

6

你可以使用塊爲。例如,

void forCount(NSUInteger count, void(^block)()) { 
    for (NSUInteger i = 0; i < count; i++) block(); 
} 

,它可以用來像:

forCount(5, ^{ 
    // Do something in the outer loop 
    forCount(10, ^{ 
     // Do something in the inner loop 
    }); 
}); 

被警告說,如果你需要寫的塊之外聲明變量,你需要指定__block存儲預選賽。

4

上可能是使用dispatch_apply()

dispatch_apply(25, myQueue, ^(size_t iterationNumber) { 
    ... do stuff ... 
}); 

注意,這同時支持併發和同步執行,這取決於是否myQueue是併發的隊列或你自己創造的連續隊列中的一個。

0

僅供參考,您可以用一個定義下面的代碼合併,或寫一些東西,爲讀者的效果:

//Assign an integer variable to 0. 
      int j = 0; 
      do{ 
       //do something as many times as specified in the while part 
      }while(++j < 20); 
相關問題