私はVisual Studio 2017のネイティブモードでC++を使用しています。そのコンパイラーは以下のステートメントを問題なくコンパイルします。
const char * AnArrayOfStrings[] = {"z1y2x3w4", "Aname"};
ただし、上記のステートメントを変更して、charが符号付きまたは符号なしであることを指定すると、コンパイラーはC244エラーを発行します。たとえば、次のステートメントはnotコンパイルします。
const signed char * AnArrayOfStrings2[] = {"z1y2x3w4", "Aname"};
const unsigned char * AnArrayOfStrings2[] = {"z1y2x3w4", "Aname"};
Charの符号を明示的にすると、コンパイラがステートメントのコンパイルを拒否する理由がわかりません。
私の質問は:コンパイラがこれらのステートメントのコンパイルを拒否したために見逃してしまった正当な理由はありますか?
ご協力ありがとうございます(C++のドキュメントであるStackOverflowで調査を行い、Googleを使用し、自分で答えを見つけるために数十のC/C++の本について相談しましたが、それでも理由がわかりません。)
"z1y2x3w4"
はconst char[9]
であり、const char*
からconst signed char*
への暗黙的な変換はありません。
reinterpret_cast
を使用できます
const signed char * AnArrayOfStrings[] = {reinterpret_cast<const signed char *>("z1y2x3w4"),
reinterpret_cast<const signed char *>("Aname")};
上記のコードをコンパイルすると
const signed char * AnArrayOfStrings2[] = {"z1y2x3w4", "Aname"};
cでgccを使用してオプション-Wall
を使用すると、次の警告が表示されます
test.c:5:49: warning: pointer targets in initialization differ in signedness [-Wpointer-sign]
const unsigned char * AnArrayOfStrings2[] = {"z1y2x3w4", "Aname"};
^
test.c:5:49: note: (near initialization for 'AnArrayOfStrings2[0]')
test.c:5:61: warning: pointer targets in initialization differ in signedness [-Wpointer-sign]
const unsigned char * AnArrayOfStrings2[] = {"z1y2x3w4", "Aname"};
AnArrayOfStrings2
と"z1y2x3w4"
の要素のタイプは異なります。 AnArrayOfStrings2[0]
はconst signed char *
タイプであり、"z1y2x3w4"
はconst char[9]
タイプです。
C++では同じコードでエラーが発生します。 C++で機能させるには、明示的なキャストが必要です。
理由を説明する
const char * AnArrayOfStrings[] = {"z1y2x3w4", "Aname"};
簡単な例をとります
const char c[] = "asc";
const char *p1 = c; // OK
signed const char *p2 = c; // Error
unsigned const char *p3 = c; // Error
上記のスニペットの2行目で、c
はconst char *
に変換され、p1
とc
は互換性のある型になります。
3行目では、p2
とc
のタイプに互換性がなく、コンパイラーはC++でエラー(Cの警告)を発生させます。同じことが4行目でも起こります。
int
タイプの別の例を考えます
const int i[] = {1,2,3};
const int *ii = i // OK
signed const int *si = i; // OK
unsigned const int *usi = i; // Error
最初の2つのポインタ初期化は、指定子なしでint
として機能しますが、signed int
と同等です(ただし、char
には当てはまりません)。したがって、型に互換性があります。 const int *
またはsigned const int *
はunsigned const int *
と互換性がないため、最後のケースで初期化は失敗します。