Cプログラミング入門

第6回 Chapter 2 Cプログラミング最初の一歩~Hello Worldからはじめよう(4)

この記事を読むのに必要な時間:およそ 3 分

文字列とは

hello.cの"Hello World\n"のように,ダブルクォーテーション(")で囲まれた文字の集まりのことを文字列といいます。文字列の後ろに付いている\n改行コードを表すC言語の拡張表記です。つまり,printf()による文字列の表示の際には,画面上で直接見える「Hello World」の文字列の直後に,改行コードが出力されているのです。

この改行コードは,メッセージの表示の際には通常必要です。改行コードがないと,実行終了後のシェルのプロンプトの位置がおかしくなったり,また,出力のバッファの関係で意図したタイミングで文字列が表示されないことがあります。

バックスラッシュ(\)を使った文字コードの拡張表記には,改行コードの\nのほかに,いくつかの表記があります。詳しくはアスキーコード表を参照してください。これらの拡張表記は,コントロールコードのように,画面に直接表示できない文字を表記するために使用されます。さらに," "で囲まれた文字列中で「"」を使いたい場合は\"と表記し,\自体は\\と表記します。

なお,バックスラッシュ(\)はOSや環境設定によっては(\)に見えますが,文字コード自体は同じであり,単に表示上の問題であるため,どちらも同じものと考えてください。

表2.1 バックスラッシュ(\)を使ったおもな拡張表記

表記実際の文字コード
\n改行コード
\""
\\\

ソースファイルはフリーフォーマット

C言語のソースファイルには,基本的には行の概念がありません。これは,アセンブラなどの行単位で記述されたソースファイルとは異なるところです。そもそも行というのは,改行コードで区切られた文字列ですが,C言語の文法では,改行コードだけでなく,スペースもTABも,みな同じように,単なる区切りのための文字として扱われます。つまり,改行の代わりにスペースを使って1行につなげても,逆にスペースだったところで改行して2行に分けても,C言語のプログラムとしてはまったく等価なのです。

hello.cの改行位置などを変えて記述した奇妙なソースファイルの例を,リスト2.5(hello_strange_1.c)およびリスト2.6(hello_strange_2.c)に示します。これらはどちらも,もとのhello.cとC言語の文法的に等価です。

リスト2.5 hello_strange_1.c

#include <stdio.h>
int main(){printf("Hello World\n");return 0;}

リスト2.6 hello_strange_2.c

#include <stdio.h>
             int
            main
           (
          )
         {
        printf
       (
      "Hello World\n"
     )
    ;
   return
  0
 ;
}

このようにC言語のソースファイルは,プログラマが任意に改行・スペース・TABを入れてフリーのフォーマットで記述することができますが,一般的にはC言語の構文がわかりやすいようにインデント(字下げ)を行うなどの習慣があります。具体的には関数内や,次回以降に扱うif,for,whileなどの構文内では,行頭に複数のスペースまたはTABを入れてインデントします。ただし,具体的なソースのスタイルには,プログラマの好みの問題もあり,絶対的な基準はありません。

なお,#includeなどのプリプロセッサのための行はフリーフォーマットではなく,⁠#」は行の左端に書いて行の概念を持って記述しなければなりません。

#defineを使ってみる

「#include」のほかに「#define」というプリプロセッサの指令もあります。⁠#define」を使えば,任意のマクロを定義して,プログラム中の文字列を置き換えることができます。たとえば,

#define MESSAGE "Hello World\n"

と定義しておけば,プログラム中にMESSAGEというマクロ名を書くと,それはコンパイル前に"Hello World\n"と展開されます。

hello.cを,⁠#define」を使って書いた例をリスト2.7に示します。このように書いても,もとのhello.cとまったく同じプログラムとして動作します。

リスト2.7 hello_define.c

#include <stdio.h>

#define MESSAGE "Hello World\n"

int
main()
{
  printf(MESSAGE);
  return 0;
}

「#define」による文字列の置き換えは,C言語の文法とは関係なく行なわれます。⁠#define」は,定数値をマクロとして定義したり,マクロ関数を定義したりするのに使われます。なお,定数値を「#define」で定義する場合は,マクロ名を習慣的に大文字とします。

printf()以外の関数を使う方法

hello.cでは,⁠Hello World」というメッセージを表示するのに,

printf("Hello World\n");

という関数を使用しました。しかし,単にメッセージを表示するだけなら,標準ライブラリ関数のprintf()以外の関数を使うこともできます。たとえば,

fputs("Hello World\n", stdout);

や,

puts("Hello World");

という関数を使っても,同様に「Hello World」というメッセージを表示します。

fputs()関数の2番目の引数に書いてあるstdoutは,標準出力を表しており,これはインクルードしているstdio.hの中で定義されています。また,puts()関数の場合は,関数側でメッセージの最後に改行コードを付けてくれるため,printf()やfputs()とは違って,最後の\nを付ける必要がありません。

著者プロフィール

山森丈範(やまもりたけのり)

「C言語はアセンブラを触っているうちに自然に覚えてしまった」というプログラマ。C言語とのかかわり上,OSは専らUNIXを使用。C言語のプログラムでは,いつもLinux/FreeBSD/Solarisすべてで動くことを気に留めている。C言語と同様に移植性の高いシェルスクリプトにも思い入れが深く,著書に『シェルスクリプト基本リファレンス』がある。

著書