第26問の答え

答え

C++の予約語にあたるdeleteが関数名になっている!
bool delete(char *pText) {
  ……
}
C++の予約語はC言語でも使わないほうがベター!
bool DeleteLastLetter(char *pText) {
  ……
}

解説

C言語では、いくつかの単語が「予約語」に指定されています。予約語は、変数名や関数名などの「識別子」に使うことができません。

例えば、次のようにif()という名前の関数を書くとエラーになります。

void if(bool condition) { /* エラー:「if」は関数名にできない! */
  ……
}

次のように、変数の名前をswitchとするのもエラーです。

  bool switch = true; /* エラー:「switch」は変数名にできない! */
さすがにこういう名前は付けないと思いますけど。
そうよね。そもそもコンパイルエラーになるから、すぐに気付くしね。
ですよねぇ。
でも、エラーにはならないけれど、使わないほうがいい名前もあるの。

C言語のものに加えて、C++にはさらにいくつかの予約語があります。例を挙げると、newdeleteclassthisなどが予約されています。

問題のプログラムには、delete()という関数が使われていましたね。

bool delete(char *pText) { /* ← deleteはC++の予約語! */
  ……
}

これは、C言語のプログラムとしては問題ありません。でも、先々のことまで考えるなら、早めに別の名前に変えておいたほうがいいでしょう。C言語のプログラムを、そのままC++に流用(いわゆる「移植」)したくなるケースも少なくないためです。

bool DeleteLastLetter(char *pText) { /* ← 別の名前に変えておこう! */
  ……
}
それって、実際にC++に移植するときにやればいいんじゃないんですか?
それでもいいわよ。でもね、「これC++の予約語じゃん!」って気付いていたとしたらどう?
あー、そのまま放置するのは、ちょっと気持ち悪いかも……
あと、そもそもdelete()っていう関数名はどうなのかしらね?
うーん、ちょっと何をする関数なのか分かりづらいし、予約語かどうか以前にかぶりやすい名前かも……
でしょう?だからね、こういうのは早めに直しちゃったほうがいいのよ。
直さなかったら、どうなるんですか?
その関数を呼び出す部分が増えていって、だんだん直すのがメンドウになっていくわね。
そっか。だから「早めに直す」わけですね!
ここがポイント!
変数や関数には、予約語を避けつつ、分かりやすい名前を早めに付けておこう!

ちなみに。

アンダースコア(_)で始まる名前も、特別な理由がない限り使わないほうが無難です。具体的には、次のようなものです。

int _MyVariable = 123; /* _で始まる変数名は避ける */

void _MyFunction(void) { /* _で始まる関数名は避ける */
  ……
}

こうした名前は、ライブラリなどが独自に使用できるようにするために予約されています。C言語の文法としては問題ないのですが、自分で付けた名前とライブラリ内の名前が衝突するとエラーになってしまいます。

また、アンダースコアを2つ以上つなげた名前も避けたほうがいいでしょう。この書き方も、開発環境によっては予約されている場合があります。

#define MY__MACRO /* __を含む名前も避けたほうがいい */
こういう名前も、普通はあんまり付けないんじゃないですかね。
だといいのだけど、そうでもないのよ。
例えば、typedefと一緒に_が使われるケースは多いわね。
typedef enum _MyEnum {
  ……
} MyEnum;

typedef struct _MyStruct {
  ……
} MyStruct;
あ、見たことあるかも!
でしょ?そういうルールでやってる開発チームもあるもの。
でも、こう書くルールにしたほうが無難ね。
typedef enum {
  ……
} MyEnum;

typedef struct {
  ……
} MyStruct;
あ、はい。前に別の問題で練習したやつですね!
そうそう、よく覚えてたわね。えらい!
えへへ(褒められた〜!)

修正後のプログラム

main.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

bool DeleteLastLetter(char *pText) {
  size_t length = strlen(pText);
  if (length > 0) {
    pText[length - 1] = '\0';

    return true;
  }

  return false;
}

int main(void) {
  char text[] = "Hello!!";
  while (DeleteLastLetter(text)) {
    printf("deleted: %s\n", text);
  }

  return EXIT_SUCCESS;
}
実行結果
deleted: Hello!
deleted: Hello
deleted: Hell
deleted: Hel
deleted: He
deleted: H
deleted: