文字列リテラルの型

ロベールのC++入門講座 05-13

文字列リテラルの型は正確にはconst char型の配列だそうです。

てっきりポインタ型だと思っていました。

自分の目で確認するため、sizeofしてみました。

#include <iostream>
using namespace std;

int main () {
    cout << sizeof("foo bar baz") << endl;
    
    return 0;
}
$ main
12

確かにサイズが取れています。もしchar*型だったならせいぜい4バイト程度のはずです。

ですがここで一つ問題があります。

もしconst char型の配列なのだとしたら、char*型でアドレスを取れるはずがありません。以下のコードを見てください。

#include <iostream>
using namespace std;

int main (void) {
    const char str[] = "foo bar baz";
    char* p = str;
    
    return 0;
}
$ cl /W4 /EHsc main.cpp
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
main.cpp(6) : error C2440: '初期化中' : 'const char [12]' から 'char *' に変換できません。
        変換で修飾子が失われます。

このようにコンパイルエラーになるはずですが、文字列リテラルの場合はコンパイルエラーになりません。

int main (void) {
    // const無しのchar*に代入してるのに何故かコンパイルが通る
    char* p = "foo bar baz";
    
    return 0;
}

どうやらこれは、C言語との互換性のために無理やり通るようになっているようです。

そもそもC言語ではconst char型の配列であっても、const無しのchar*型へ代入できてしまいます。警告こそは出るものの、コンパイルエラーにはならないんですね。

ということでもしC++で文字列リテラルのconst付きを一気に強化しちゃったら動かなくなるCのコードが大漁に出る羽目になるのでこういった処置がとられてるんでしょうね。

ただ将来的なC++ではこの救済処置は廃止される予定らしいので今のうちからconst付きのchar*型を意識付けておく方が良さそうです。