Почему C++ не принимает подписанный или неподписанный символ для массивов символов

Я использую C++ в основном режиме с Visual Studio 2017. Этот компилятор компилирует выражение ниже без жалобы:

const char * AnArrayOfStrings[]  = {"z1y2x3w4", "Aname"};

Однако, если я изменил вышеприведенный оператор, чтобы указать, что char подписан или неподписан, компилятор испускает ошибку C2440. Например, приведенные ниже утверждения не компилируются:

const signed   char * AnArrayOfStrings2[] = {"z1y2x3w4", "Aname"};

const unsigned char * AnArrayOfStrings2[] = {"z1y2x3w4", "Aname"};

Я не вижу причины, по которой компилятор отказывается компилировать инструкцию, когда знак char становится явным.

Мой вопрос: есть ли веская причина, по которой я не видел, чтобы компилятор отказался компилировать эти утверждения?

Спасибо за вашу помощь (я проводил исследования в StackOverflow, документации C++, я использовал Google и консультировался о десятках книг C/C++, пытаясь найти ответ сам, но причина по-прежнему не ускользает от меня).

Ответ 1

"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")};

Ответ 2

Если вы скомпилируете приведенный выше код

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

Во второй строке вышеприведенного фрагмента c преобразуется в const char * что делает p1 и c совместимыми типами.
В третьей строке тип 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  

Первые две инициализации указателя работают как int без какого-либо спецификатора, эквивалентно signed int (но это не так для char), и поэтому типы совместимы. Инвализация завершается в последнем случае, поскольку const int * или signed const int * несовместим с unsigned const int *.