主にiOSアプリを作っています。

ぱるにゃん

iOS サポート

Cをすっ飛ばしてきた人のための「いまさらのC」

投稿日:

iOS Advent Calendar 2011、18日目はわたくし@palnyanが担当します。

さて、わたしは札幌でiPhone Dev Sapporoに参加しています。詳しい(?)活動内容は@iphone_dev_sapを参照していただけるとよいかと思いますが、毎月のApple Store Sapporoでのイベントや、隔月で勉強会などを開催しています。その中で、広く募集をしているわけではありませんが数名でほぼ毎週、早朝勉強会(7時〜)や夜勉強会(22時〜)をやっています。これは、「ある程度iOSアプリを開発してきたけど基礎の抜けているところを補完したい」といった目的で始まりました。

iOS開発は参入しやすかったのか、Objective-Cが初めてのプログラミング言語、といった感じの方が多く、Cすら触れてないからこその疑問とかをよくぶつけられるのです。

高校や高専で情報系の学科へ進学すると、大抵「はじめてのC」とか「やさしいC」とか、いかがわしい名の本で勉強します。そんな、Cを経験してこなかったObjective-Cerのために、今さらな感じのエントリーを書いてみます。

+とか-とか*とか<=とか|とか

自分で調べたくても検索エンジンがはじくこいつら。ひっくるめて演算子と言います。演算子でググればきっと一覧が出てきます。いろいろおもしろいのがありますよ。加減乗除と比較演算子くらいしか使ってないともったいないです。

三項演算子かわいいよ三項演算子

NSLog(@"flag:%@", flag ? @"YES" : @"NO");

この「?:」というのが三項演算子。はてなの前(1項目)の式を評価し、trueなら2項目、falseなら3項目を返すという感じです。

これは、

NSString *str;
if (flag) {
str = @"YES";
}
else {
str = @"NO";
}
NSLog(@"flag:%@", str);

とだいたい同じです。三項演算子はスマートですね。三項演算子は好き嫌いが分かれて禁止されてる会社もあるとかないとか。独学だと、演算子でググらなけりゃ出会うことがないであろうこいつは個人的には大好きです。わたしは多くの場合使った方がいい派ですが、三項演算子の入れ子はちょっとどうかと思います。

iを10で割った余りを英語で返す。

int d = i % 10;
NSLog(@"%@", d==0?@"zero":d==1?@"one":d==2?@"two":d==3?@"three":d==4?@"four":d==5?@"five":d==6?@"six":d==7?@"seven":d==8?@"eight":@"nine");

こんなコードはさすがにもげる。

インクリメント、デクリメント

書籍などではi++、i--がよく出てくる。似てるけどめったに出てこないのは++i、--i。どちらもほぼ同じなのだけど、

int i = 0;
i++;
NSLog(@"%d", i); // 1
int j = 0;
++j;
NSLog(@"%d", j); // 1

以下のような場合は違ってくる。

int i = 0;
NSLog(@"%d", i++); // 0
int j = 0;
NSLog(@"%d", ++j); // 1

利用してからインクリメントするか、インクリメントしてから利用するか、状況に応じて。

for文の すごい キモさ

一般的なfor文は
for(初期化式;条件式;変化式) {処理}
という感じですね。

for (int i = 0; i < 100; i++) {
NSLog(@"%d", i);
}

みたいな。でもfor文て、実は何も書かなくてもいいし、

for (;;) {
// 無限ループ注意
}

一部分抜けてたり(次の例は変化式がない)、処理が1行以下なら波括弧はなくてもいいし、

for (int i = 0; i < 100😉 NSLog(@"%d", i++);

いっぱい書くこともできる。

// これは何をしているかな?
for (int i=0, d=i%10; i<100; NSLog(@"%@", (d=i++%10)==0?@"zero":d==1?@"one":d==2?@"two":d==3?@"three":d==4?@"four":d==5?@"five":d==6?@"six":d==7?@"seven":d==8?@"eight":@"nine"));

キモいですね、用法用量を守って使いましょう。ちなみに教育現場的プログラミングでは課題としてキモさを競う場合がよくあります。1行プログラミングとか。

ifとswitchの使い分け

よく聞かれる代表っぽいやつ。やっちゃあかんのは例えばこういうやつ。

NSString *str;
for (int i = 0; i < 100; i++) {
int d = i % 10;
if (d == 0) str = @"zero";
else if (d == 1) str = @"one";
else if (d == 2) str = @"two";
else if (d == 3) str = @"three";
else if (d == 4) str = @"four";
else if (d == 5) str = @"five";
else if (d == 6) str = @"six";
else if (d == 7) str = @"seven";
else if (d == 8) str = @"eight";
else if (d == 9) str = @"nine";
NSLog(@"%@", str);
}

こう書くと、dが9の場合全部のif else ifを評価して最終的にd==9でひっかかるという超ムダなことに。最近のハードは優秀だからちょっとやそっとじゃ処理速度に大差は出ないのだけど、まぁアホっぽいのでswitchを使おう。

NSString *str;
for (int i = 0; i < 100; i++) {
int d = i % 10;
switch (d) {
case 0:
str = @"zero";
break;
case 1:
str = @"one";
break;
case 2:
str = @"two";
break;
case 3:
str = @"three";
break;
case 4:
str = @"four";
break;
case 5:
str = @"five";
break;
case 6:
str = @"six";
break;
case 7:
str = @"seven";
break;
case 8:
str = @"eight";
break;
case 9:
str = @"nine";
break;
}
NSLog(@"%@", str);
}

この場合はdの値が0でも9でも評価は1回なので速い。整数値で多く(3〜4つくらい以上)パターンがある場合はswitchの方がいいです。

評価回数の話のついでに

すべての評価式がtrueである必要があるif文なんかは、falseになった時点で評価を終了するので、falseになる確率が高いものから書いていくと吉。あまりよい例ではありませんが、

for (int i = 0; i < 1000000000; i++) {
if (i%3==0 && i%4==0 && i%5==0) {
}
}

より

for (int i = 0; i < 1000000000; i++) {
if (i%5==0 && i%4==0 && i%3==0) {
}
}

の方が速いのです。5で割った余りが0にならない確率(80%)のほうが、3で割った余りが0にならない確率(66%)より高いですからね。

if文は代入後の比較もできる

Xcodeの昔のテンプレにこういう記述がありました。

- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}

今は大体こうなってますね。

- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame]
if (self) {
// Initialization code
}
return self;
}
if (self = [super initWithFrame:frame]);

これだけで代入直後のselfを比較できるのです。コンパイラの設定が厳しいと警告やエラーが出たりしますが、その場合も

if ((self = [super initWithFrame:frame]));

とすれば大丈夫です。

if文だけでなく評価式全般で使えます。これも好みですが、個人的には昔のテンプレの方が好きです。

// さっきと何が違うかな?
for (int i=0, d=i%10; ++i<100; NSLog(@"%@", (d=i%10)==0?@"zero":d==1?@"one":d==2?@"two":d==3?@"three":d==4?@"four":d==5?@"five":d==6?@"six":d==7?@"seven":d==8?@"eight":@"nine"));

知ってる?printf

変数の値をNSLogでコンソールに出力してデバッグ、なんてことはしていると思うけど、「いらない日時やプロジェクト名まで出力されて幅取られて見づらいもげる」と思う人も多いのでは。そんな時に素敵なのがprintf!ホントに出力したいものだけ出力してくれます。

例えばこんな九九一覧。

for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
NSLog(@"%d * %d = %d", i, j, i*j);
}
}

出力結果

2011-12-18 01:28:18.223 Untan[49344:f803] 1 * 1 = 1
2011-12-18 01:28:18.224 Untan[49344:f803] 1 * 2 = 2
2011-12-18 01:28:18.224 Untan[49344:f803] 1 * 3 = 3
2011-12-18 01:28:18.225 Untan[49344:f803] 1 * 4 = 4
    :略
2011-12-18 01:28:18.269 Untan[49344:f803] 9 * 6 = 54
2011-12-18 01:28:18.280 Untan[49344:f803] 9 * 7 = 63
2011-12-18 01:28:18.282 Untan[49344:f803] 9 * 8 = 72
2011-12-18 01:28:18.283 Untan[49344:f803] 9 * 9 = 81

うぜぇ!

ということでprintfを使ってみましょう。

for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
printf("%d * %d = %d\n", i, j, i*j);
}
}

出力結果

1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
1 * 4 = 4
    :略
9 * 6 = 54
9 * 7 = 63
9 * 8 = 72
9 * 9 = 81

So cute!!

printfの引数はNSStringではないので@""ではなく""なので注意。また、行末改行がデフォのNSLogと違い、printfは改行してくれない不親切設計なので、改行したい場合は改行コードを自分で書く必要があります。

でも、勝手に改行されないからこそできることもあります。

printf("   1  2  3  4  5  6  7  8  9\n");
for (int i = 1; i <= 9; i++) {
printf("%d", i);
for (int j = 1; j <= 9; j++) {
printf(" %2d", i*j);
}
printf("\n");
}

出力結果

   1  2  3  4  5  6  7  8  9
1  1  2  3  4  5  6  7  8  9
2  2  4  6  8 10 12 14 16 18
3  3  6  9 12 15 18 21 24 27
4  4  8 12 16 20 24 28 32 36
5  5 10 15 20 25 30 35 40 45
6  6 12 18 24 30 36 42 48 54
7  7 14 21 28 35 42 49 56 63
8  8 16 24 32 40 48 56 64 72
9  9 18 27 36 45 54 63 72 81

対応するものが横に表示されればデバッグ効率上がるのになぁなんてことがあったかもしれませんね。ないかもですね。

iOS Advent Calendar……?

「iOS関係なくね?」とか思った方も多いはず。けれど、これらをすっ飛ばしてきた人と多く出会ってきたのもまた事実なのです。知ってほしいので書いてみました。

おまけ

Objective-Cであれを書く

NSArray *english = [NSArray arrayWithObjects:@"zero", @"one", @"two", @"three", @"four", @"five", @"six", @"seven", @"eight", @"nine", nil];
for (int i = 0; i < 100; i++) {
NSLog(@"%@", [english objectAtIndex:i%10]);
}

物足りなかった方、すみません。もしこれらに興味を持った方がいたら、ぜひObjective-CにこだわらずCの入門書も1冊、手に取ってみてください。

明日は@inonbさん。ロケタッチ愛用しています!

宣伝。

Software Design 2011年12月号にすこし寄稿させていただきましたのでぜひ。

palnyan.com 記事下 336x280

palnyan.com 記事下 336x280

-iOS, サポート

Copyright© ぱるにゃん , 2017 AllRights Reserved.