第 5 回 第4回へ 第6回へ 目次へ
2006 / Aug / 9
はじめに
 このサイトは、プログラミングが始めての方やC言語を学習されていない方を対象に、Macのプログラミングの手法の中から「 Cocoa (ココア)」と呼ばれるものを紹介しています。
 プログラムは、プログラミング言語によって書かれているということはご存知だと思います。Cocoaでは、Objective-C言語というC言語を発展させたプログラミング言語を使用しています。この「Objective-C Primer」では、Objective-C言語を理解する上で必要となるC言語の基礎を学習して、Objective-CとCocoaの入り口までご案内することを目指しています。

ご注意  このサイトに書かれているサンプルコードの実行はあなたの自己責任において行ってください。このサイトおよび私は、このサイトのサンプルコードの実行によって発生するいかなる損害にも責任がなく保証もいたしません。

2006年9月8日修正
2006 / Aug / 11
NSLog ( )
NSLog( )関数の使い方

 今後、プログラムの実行結果を確認するために、この関数を多用するとことになると思います。
NSLog( ) は、ログ画面に文字列を表示する関数です。表示する際に変数の値などを、指定した書式で文字として表示することができます。なお、変数については、次の項で詳しく説明いたしますので、ここではこのまま読み続けてください。

NSLog(@"I like Mac mini.") ;
日付時刻などの行に続けて「I like Mac mini.」と表示されたと思います。 " と " に囲まれた間が文字列として解釈されます。なお、はじめの " の前に@を入れることを忘れないでください。@により、それに続く文字列がNSStringオブジェクトになります。取りあえずここでは、@を必ず入れなければならないと覚えてください。

NSLog(@"\n I like Mac mini.") ;
これで、単独の行に「 I like Mac mini.]と表示されたと思います。\nとI like 〜の間にスペースを入れているのは、たんにコードを読みやすくするためです。スペースは入れなくても大丈夫です。\ とそれに続く文字(1〜2文字)はエスケープシーケンスと呼ばれ、特別な働きをします。

NSLog(@"\n I like \"Mac mini\".\t But, mine is \"Intel Mac mini\".") ;
I like "Mac mini".     But, mine is "Intel Mac mini".
\n は改行を、\" で"文字列"に囲まれた中で「 " 」を使用できるようにします。\t は、タブを空けます。

float ghz = 1.5
NSLog(@"\n It is %f GHz.", 1.5) ;
NSLog(@"\n It is %.1f GHz or %.2f GHz", ghz, 1.666666) ;
「 % 」とそれに続く文字は変換仕様と呼ばれます。
%f は浮動少数点数を文字列に変換して表示します、その際にカンマ「 , 」以降に変換したい値のリテラル値か変数を記入します。上記のようにカンマで区切って変換したい値を複数指定することもできます。
実行結果は、
It is 1.500000 GHz.
It is 1.5 GHz or 1.67 GHz.
となります。
1行目では、変換仕様の %f で、リテラル値の 1.5 を浮動少数点数として表示しています。デフォルトでは小数点以下6桁まで表示されます。
2行目では、まず%.1fと変換仕様の精度を小数点以下1桁まで表示するようにオプション指定してから変数ghzの値を表示しています。そして次に%.2fとして小数点以下2桁まで表示する指定でリテラル値の1.666666を表示しています。桁を縮める際に丸め(四捨五入)が行われていることが分かります。

ほかによく使われる変換仕様として、%d %s %@ などがあります。%d は整数値を、%s では文字列を表示します。%@ についてはまた後の回で説明します。

変換仕様のオプション
%10d とすると、10進数の整数値を10桁で表示します。値が6桁なら、その前に4桁の空白が付きます。
%-10d とすると、10進数の整数値を左寄せで表示します。値が7桁なら、数字の後に3桁の空白が付きます。%010d では、先攻する空白部分を0で埋めます。値が5桁ならそれに先攻して0を5つ表示します。
浮動小数点数の場合は、%08.2f とすれば123.123の場合 000123.12 と表示されます。%08.2f の8が小数点以下も含めての全体の桁数になっている点に注意してください。
2006 / Aug / 9
変数
2006 / Aug / 17 加筆

【変数・へんすう】数を代表する文字がその値をいろいろとり得るとき、その文字をいう。x・y・z などで示されることが多い。大辞林 第二版より

前回は、上記を引用して、変数とは値の事を指すのではなく値に付けられた名前のことを指す。と言いました。これをコンピューター上の話しに戻して具体的に説明していきます。

変数はリテラル(直定数)とは違い、いきなり使うことはできません。まず、
    1.    どういう種類の値を使うのか
    2.    その値になんという名前を付けるのか
以上の2つのことを決めて、メモリー上にその値のための場所を確保します。このメモリー上の場所というのを、コンピューターは数値(番地番号:アドレス)として管理しています。しかし人間は数値より具体的な名前のほうが分かりやすくて覚えやすいので名前を付けます。この名前とメモリー上の番地番号との結びつけは、システム(OS)とプログラムが通常は私たちの目に触れない所で管理します。
 なお、メモリー上に場所を確保すると言っても、決してむずかしいことではありません。あとで述べる「変数の宣言文(宣言式)」というのを記述すれば、あとはプログラムとシステムが自動でやってくれます。

 値の種類はデータ型 (がた・かた)と呼ばれています。Objective-Cでおもに使われているデータ型は、
文字型 (char)、整数型 (int)、浮動少数点数型 (float)、倍精度浮動少数点数型 (doble)、真偽値型 (BOOL)、および オブジェクト型 (id) です。BOOLはC言語からObjective-C言語へ移行するときに少し変更が加えられています。id型は Objective-Cで新しく導入されたデータ型です。文字列は、Objective-CではNSStringというクラスのオブジェクト(インスタンス)を使います。

 変数の名前には、アルファベットの大文字小文字と0から9までの数字およびアンダースコア(アンダーバー)「 _ 」が使えます。ただし名前の先頭に数字は使えません。そしてアンダースコアではじまる名前も開発環境 (IDEやフレームワークなど)が、内部で使っている識別子名(関数名、変数名、その他)で指定されている場合がほとんどなので、アンダースコアを先頭で使うことは推奨されていません。またアルファベットの大文字と小文字は別の文字として区別されます。ご注意ください。
 なおCocoaプログラミングの命名規則では変数名とメソッド名(C言語でいう関数です)はアルファベットの小文字ではじめ、複数の単語で構成される場合は、最初の単語を小文字ではじめて、次の単語からは、先頭文字だけを大文字にするように推奨されています。

      例 : complexVariableIdentifier

当然、変数名の途中でスペース(空白)を使うことはできません。単語の区切りとしてアンダースコア「 _ 」を使うことはクラッシック時代には多く見かけましたが、現在ではほとんど使われていません。なお、この小文字ではじめる大文字ではじめるというのは、Objective-C言語の仕様 (決まり事) ではありません。守らなくてもプログラムは実行されます。しかし長年の経験で積み上げられた命名規則なので遵守するほうが実際に楽です。

では、変数の宣言文(式)を書いてみましょう。

      int      argc ;

これで int型 (整数型)の argc という名前の変数をメモリー上に確保したことになります。
同じ型の変数であれば、カンマ「 , 」で区切って複数個を同時に宣言することもできます。
 なお、 int 型については、 C言語 予約語 一覧 で詳しく説明しています。ご欄になってください。

      float    floatValueA, floatValueB, floatValueC ;
 
これで、float型 (浮動少数点数型) の変数を3個確保したことになります。
 なお、 float 型については、 C言語 予約語 一覧 で詳しく説明しています。ご欄になってください。

これらの変数は、宣言しただけでは中に値が入っていません。というか正確には変数として確保される前からそのメモリー上に存在していたゴミ値と呼ばれる値が入っています。プログラムで正しく使うには、正しい値を入れなければなりません。これを初期化といいますが、変数の宣言と同時に初期化を行うこともできます。なお初期化で与える値はリテラル値でも、あるいは別の変数の値でも構いません。

      float    floatValue  = 5.12 ;
      double   doubleValue = floatValue ;

上記の例では、まずfloat型の変数floatValueを、宣言と同時に5.12というリテラル値で初期化しています。
そして次の行でdouble型変数doubleValueを、宣言と同時にfloatValue変数の値で初期化しています。
「変数はその値に付けられた名前」と表現しましたが、実際に変数名だけを記述した場合は変数が表している値で置き換えられます。
 また、すべてのデータ型の変数に言えることですが、変数の宣言だけをしておき、初期化は後で行うという使いかたのほうが一般的に多いみたいです。
 なお、 double 型については、 C言語 予約語 一覧 で詳しく説明しています。ご欄になってください。

 上記の3つのデータ型以外にも予約語では、char型というデータ型が定義されています。これは英語などの1バイト文字を扱うのを本来の目的としたデータ型ですが、Objective-Cではcharを文字を表すデータ型として使う機会はあまり多くありません。Objective-Cでは文字および文字列は NSString クラスのオブジェクトとして保持するからです。
 なお、char 型については、 C言語 予約語 一覧 で詳しく説明しています。ご覧になってください。

argc        = 55 ;
      floatValueA = floatValueB = floatValueC = 6.14 ;

上記の例の1行目では、すでに宣言されている int型変数のargcに、55というリテラル値を代入(初期化)しています。2行目では、3つのfloat値を一度に初期化(代入)しています。代入 (だいにゅう)という言葉を使いましたが、変数は何度でも値を変えることができますので、普通は最初の時か、もしくは改めて始めるときにだけ初期化と呼ばれます。「 = 」は、「 = 」 の右側の値を「 = 」の左側に入れる(代入)するという意味で使われます。等価という意味での記号は、==が用いられます。なお、このような記号の事をプログラミング言語では、演算子 (えんざんし)と呼んでいます。

関数内 (main関数を含む )およびメソッド内におけるすべての変数の宣言は、変数の宣言以外のすべて実行式(文)の前に行われなければなりません。変数の宣言と同時に初期化を行う場合を除き、たとえ値の代入であっても実行式のあとでは変数の宣言をするとエラーになります。すべての変数の宣言は、関数 (メソッド)の1番最初にまとめて記述するようにしましょう。

      int      intValue = 1234;   // ここで変数の宣言と初期化を同時に行っていますが
      float    floatValue ;       // ここでの変数の宣言はエラーにはなりません
      float = 123.456 ;    // しかしここで変数への値の代入だけの式を実行してしまうと
      double   doubleValue ;      // この変数の宣言はエラーとなってしまいます

では、第3回の「コマンドラインツールの作成」第4回の「Objective-C言語への移行」を参考にして、新しく「val」というプロジェクトを作って下さい。今回は「main.c」を「main.m」に名称変更してみましょう。「Foundation.framework」をプロジェクトに追加することも忘れずに行ってください。もし面倒であれば、そのままfumc.mを使って頂いても結構です。
 またNSLog( )関数の使い方は前項の NSLog( )関数の使い方 を参考にしてください。

 では、main.m を次のように書き換えてみましょう。

main.m

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    NSLog(@"\n %s", argv[argc - 1]);
    NSLog(@"\n argc is %d", argc);
    argc = 55;
    NSLog(@"\n argc is %d", argc);
    return 0;
}


上記のコードの実行結果は、
[ session started at 2006 - 08 - 09 20 : 30 :15 + 0900. ]
というような表示から始まり、
2006-08-09  20 : 30 : 15 . 391  val [ 1554]
という日付と時刻およびプログラム名が表示される行を1行ずつ挟みながら、

/Users/ユーザ名/Desktop/vivacocoa/val/build/Debug/val
argc is 1
argc is 55

のようになると思います。
※上記の実行結果の1行目は実際にファイルを保存した場所により違います。

main関数ははじめからargcというint型変数と、argvという文字列の配列というものを持っています。
これはこのようなコマンドラインツールだけではなくCocoaアプリケーションやCocoaドキュメントベースドアプリケーションでも同じです。
argcには、このプログラムを起動した時に受け取った引数の数が整数値として保持されています。そしてその引数の内容ははすべて文字列としてargvという配列の中に納められています。
この例では、このプログラムが起動したときに受け取った引数の数は1つで、その引数の内容はこのプログラムの名前もしくは保存場所ということになります。
その後、argcが変数であることを証明するために、55という整数値を代入して表示しています。

main.m

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    float    floatValueA, floatValueB = 5.12 ;
    double   doubleValue = floatValueB ;
    NSLog(@"\n doubleValue is %f", doubleValue) ;
    floatValueA = 3.56 ;
    NSLog(@"\n floatValueA is %f", floatValueA) ;
    NSLog(@"\n floatValueB is %s", floatValueB);
    return 0;
}


上記の実行結果は、また日付や時刻の行を挟みながら、
doubleValue is 5.120000
floatValueA is 3.560000
floatValueB is 5.120000
のようになると思います。

main.m

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    BOOL    boolValue = NO ;
    int     intValue = boolValue ;
    NSLog(@"\n intValue is %d", intValue) ;
    boolValue = YES ;
    NSLog(@"\n boolValue is %d", boolValue) ;
    if (boolValue == true) {
        NSLog(@"\n boolValue is YES.") ;
    }
    if (boolValue) {
        NSLog(@"\n YES, I'm sure!!!") ;
    }
    boolValue = FALSE;
    if (! boolValue) {
        NSLog(@"\n NO, I'm not....") ;
    } ;
    return 0;
}


上記の実行結果は、
intValue is 0
boolValue is 1
boolValue is YES
YES, I'm sure!!!
NO, I'm not....
となります。
実行結果の1行目では、 BOOL値のNOはint(整数値)の0であることが分かります。
実行結果の2行目では、 BOOL値はそのままでもYESは1であることが分かります。
実行結果の3行目では、 BOOL値はこのようにif文での真偽値として使われる事が多いことを示しています。 他の言語系では真偽値はこのようにTRUE(true)およびFALSE(false)で表されますが、Objective-CのBOOL値もYES、NOだけではなく、通常通り TRUE(true) と FALSE(false) にも対応していることを示しています。ただし小文字の yes、no は通用しないみたいです。
実行結果の4行目では、このような真偽値は、== という等価演算子(とうかえんざんし)を用いなくても、真(しん)か偽(ぎ)を返している事を示しています。
実行結果の5行目では、論理演算子のnot演算子「 ! 」でif文が偽のときにYESを返し、真のときにNOを返すようにしています。
 なお、ここで使われている if 文については、 C言語 予約語 一覧 で詳しく説明しています。ぜひ、ご欄になってください。

main.m

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    int    intValue ;
    NSLog(@"\n intValue is %d", intValue);
    intValue = intValue + 1;
    NSLob(@"\n intValue is %d", intValue);
    intValue = 5 ;
    NSLog(@"\n intValue is %d", intValue);
    return 0;
}

2006年8月14日:ゴミ値に1をプラスする式と実行結果を追加

最後に、初期化されていない変数のゴミ値を確認してみました。

intValue is 7992
intValue is 7993
intValue is 5

この場合、宣言だけされて確保された intValue変数の中には10進数の整数値で表現すると 7992 となる値が最初から入っていたことになります。
次にゴミ値が本当に値なのか確認するために、1をプラスして計算結果を出してみました。
最後に、intValue変数に整数値の 5 を代入して表示しています。


以上で、C言語の予約語の中の、char、int、float、doubleという データ型 と、それを修飾する、short、long、signed、unsignedという型修飾子の説明をいたしました。しかしC言語の予約語の中にはBOOL型というものはありませんでした、BOOL型とは一体何なんでしょうか。次の項で実験したいと思います。
2006 / Aug / 17
BOOL型
では早速コーディングして試してみましょう。

main.m (サンプル1)

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    BOOL    boolValue ;
    boolValue = NO ;
    NSLog(@"\n boolValue is %d", boolValue);
    boolValue = YES ;
    NSLog(@"\n boolValue is %d", boolValue);
    boolValue = 2 ;
    NSLog(@"\n boolValue is %d", boolValue);
    boolValue = 127 ;
    NSLog(@"\n boolValue is %d", boolValue);
    boolValue += 1 ;
    NSLog(@"\n boolValue is %d", boolValue);
    return 0;
}


実行結果
boolValue is 0
boolValue is 1
boolValue is 2
boolValue is 127
boolValue is -128

実行結果の1行目は、boolValueに代入されたNOが整数の0であることを表しています。
実行結果の2行目は、boolValueに代入されたYESが整数の1であることを表しています。
実行結果の3行目では、boolValueに代入された2が正常に表示されています。これでBOOL型が0か1以外の整数も保持できることが分かります。
実行結果の4行目では、boolValueに char型の最高値である127を代入して無事に表示されています。
実行結果の5行目では、boolValueに、boolValueの値に1を足して代入しています。上限値を超えた値は次に最低値の-128を表示しています。

註1
boolValue += 1 とは、左のboolValueの値に右側の値1を足して代入するという意味です。
boolValue = boolValue + 1 と同じ意味になります。

 これでBOOL 型が1バイトのchar 型と同じであることが分かります。
しかし、このような面倒なことをせずに、簡単に変数が確保しているメモリのバイト数を調べることができます。それが sizeof 演算子(えんざんし)です。詳しくは C言語 予約語 一覧 を見て下さい。

 さて、BOOL 型が実際にはchar 型と同じことだと分かりました。これは一体どういう仕組みになっているのでしょうか ?
 実は、typedef キーワードという予約語によって BOOL と宣言されたデータ型が、char 型のデータとしてメモリを確保するようにしているのです。ですからC言語の予約語の中に BOOL は存在していません。
 typedef の使い方は、C言語 予約語 一覧 を見て下さい。

では、逆にchar型のままでもBOOL型の振る舞いをできるかどうかも試してみましょう。

main.m (サンプル2)

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    char    charValue ;
    charValue = NO ;
    NSLog(@"\n charValue is %d", charValue);
    charValue = YES ;
    NSLog(@"\n charValue is %d", charValue);
    charValue = 127 ;
    NSLog(@"\n charValue is %d", charValue);
    charValue += 1 ;
    NSLog(@"\n charValue is %d", charValue);
    charValue = FALSE ;
    NSLog(@"\n charValue is %d", charValue);
    charValue = TRUE ;
    NSLog(@"\n charValue is %d", charValue);
    if (charValue == YES) {
        NSLog(@"\n charValue is YES.") ;
    } else {
        NSLog(@"\n charValue is NO.") ;
    }
    return 0;
}


この実行結果は、以下のようになると思います。
charValue is 0
charValue is 1
charValue is 127
charValue is -128
charValue is 0
charValue is 1
charValue is YES.
まったくBOOL型と同じ動きをすることがわかります。
NOやYES、そしてFALSEとTRUE までも正確に0と1の数値として代入できています。そして if 文の条件式の中でも YESと等価であるかどうかの判断に使えています。

記号定数
 ここでまた疑問が出てきます。どうして FALSE や false や NO を 0 として理解でき、TRUE や tueや YES を 1 として理解できるでしょう。
 これは、プリプロセッサ (preprocessor) という機能で実現されています。例えば、コンパイル (テキストファイルで書かれたソースコードを機械語に直す作業) に先立ち、ヘッダファイルを読み込んで、あなたの書いたソースコードの前にヘッダファイルに書かれているテキストを追加する機能があります。これがすでにご存知の、

#include < stdio.h >
#import  < Foundation/Foundation.h >

などです。ここでもう一つ良く使われるプリプロセッサの機能 (このようなものをプリプロセッサ指令と呼びます)に define というものがあります。

#define YES 1
#define NO  0

このように記述すれば、コンパイルに先立ち、ソースコードの中の"YES"という文字列はすべて 1 という文字に、"NO"という文字列はすべて 0 という文字に置き換えられてからコンパイルが始まるようになっています。
 なお、BOOL値のYESNOは、Foundation.framework のなかでそれぞれ 1 0 にすでに置き換えられるように指定されています。
 このようにして、ある数値がある文字列に置き換えられたものを記号定数と呼びます。これでリテラルに続いて2つ目の定数の形が出て来たことになります。この記号定数は当然のことながら、コンパイルをし直さない限り変更することのできない定数です。
2006 / Aug / 17
Column
ここまでで、多くの新しい言葉が出てきました。少し整理していきましょう。

バイトとビット

まず、非常に基本的なことになりますが、1 バイト(byte) は、8 ビット(bit) です。1 ビット は、オン・オフあるいは 1 0 の数値しか持つことができません。そのビットが8個あれば、2の8乗で256種類の値もしくは状態を表せると言えます。しかし実際には2進法で考えるのはあまりにも非人間的なので、16進数が用いられます。 1バイトの半分の4ビットで2の4乗の16種類の値をとることができます。そして残りの4ビットも16種類の値がとれることになります。つまり1バイトは16の2乗で256種類の値を持つ事ができると言えます。なお、256と言っても、コンピューターはたいていの場合、数値を0から始めます(これを0基底もしくは0基数と言います)ので、0〜255という事になります。そしてさらに1バイト(8ビット)の場合、最初の1ビット目を符号(プラスかマイナス)に使いますので、残りの7ビットで128種類の値がとれます。そして、各数値にプラスかマイナスかの選択肢が付くことになります。ただし0基数ですので0はプラスに加えられて0〜127、マイナスが-128〜-1ということになります。
 1バイトでの話しばかりになりましたが、実際に1番良く使われる単位は4バイトでしょう。1バイトが256なら4バイトはその4乗になります。つまり約42億9千の値を保持できることになりますが、この場合もたいていは、1ビット目を符号(プラス・マイナス)に使いますので、0〜約21億、約-21億〜-1ということになります。
なお、16進数は、0123456789ABCDEFの16文字で表されます。ホームページなどを作られる方なら、この表記の方法は色を表す数値としておなじみのことだろうと思います。

C言語予約語

用途別に分けてみました、ご参考にしてください。すでに登場した予約語は太字になっています
データ型charintfloatdoublevoid
型修飾子shortlongsignedunsigned、volatile
記憶クラス指定子、auto、const、exturn、static、register
、break、continue、do、else、for、goto、ifreturn、switch、while
ラベル、case、default
キーワード、enum、struct、typedef、union
演算子sizeof
第4回へ 第6回へ 目次へ