С++ Разница между const char* и const char[]

Я прочитал вопрос о разнице между:

const char*

а также

const char[]

где какое-то время я думал, что массивы были просто синтаксическим сахаром для указателей. Но что-то меня беспокоит, у меня есть кусок кода, похожий на следующий:

namespace SomeNamespace {
    const char* str = { 'b', 'l', 'a', 'h' };
}

Я получаю, ошибка: объект масштабирования 'str' требует один элемент в инициализаторе. Итак, я попробовал это:

namespace SomeNamespace {
    const char str[] = { 'b', 'l', 'a', 'h' };
}

Это сработало, сначала я подумал, что это может быть связано с тем фактом, что дополнительная операция применяется, когда она является const char*, а GCC никогда не является поклонником операций, выполняемых вне функции (что в любом случае является плохой практикой), но ошибка, похоже, не предполагает этого. Однако в:

void Func() {
    const char* str = { 'b', 'l', 'a', 'h' };
}

Он компилируется просто отлично, как и ожидалось. Кто-нибудь знает, почему это так?

x86_64/i686-nacl-gcc 4(.1.4?) перец 19 инструментальная цепочка (в основном GCC).


person The Floating Brain    schedule 04.09.2013    source источник
comment
Один массив и один указатель.   -  person chris    schedule 05.09.2013
comment
...и если вы думаете, что они одинаковы, подумайте еще раз.   -  person WhozCraig    schedule 05.09.2013
comment
@WhozCraig Как я уже сказал, я прочитал вопрос, объясняющий, что они разные (где, как и раньше, я думал, что массивы - это синтаксический сахар для указателей и, по сути, набор перегруженных операторов).   -  person The Floating Brain    schedule 05.09.2013
comment
@chris Кажется странным, что компилятор не может разрешить это как константу.   -  person The Floating Brain    schedule 05.09.2013
comment
Последний фрагмент также не компилируется на моем clang (Apple LLVM 4.2, clang-425.0.28), так что я не знаю, что с вами. (ошибка: лишние элементы в инициализаторе скейлера), но я этого не ожидал.   -  person WhozCraig    schedule 05.09.2013
comment
@WhozCraig Странно ... Я всегда думал, что объявление указателя на массив и подобный массив было в стандарте. 0,0   -  person The Floating Brain    schedule 05.09.2013
comment
Я отсылаю вас к часто задаваемым вопросам C по этому вопросу: c-faq.com /aryptr/aryptrequiv.html   -  person kfsone    schedule 05.09.2013


Ответы (1)


Во-первых, не имеет значения, пытаетесь ли вы использовать составную инициализацию в пространстве имен или в функции: ни то, ни другое не должно работать! Когда вы пишете

char const* str = ...;

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

char const str[] = ...;

Вы определяете массив chars. Размер массива определяется количеством элементов в правой части и, например, становится 4 в вашем примере { 'b', 'l', 'a', 'h' }. Если бы вы использовали, например, "blah" вместо этого, размер, конечно, был бы 5. Элементы массива копируются в место, где в этом случае определено str.

Обратите внимание, что char const x[] может быть эквивалентно написанию char const* x в некоторых контекстах: когда вы объявляете аргумент функции, char const x[] на самом деле совпадает с char const*.

person Dietmar Kühl    schedule 05.09.2013
comment
Когда вы пишете то же самое, не должны ли вы вместо этого сказать может быть неявно преобразовано? - person IInspectable; 05.09.2013
comment
Я не знал, что это по-разному ведет себя в разных контекстах, спасибо, что прояснили это! - person The Floating Brain; 05.09.2013
comment
@IInspectable В отношении typedefs, это будет на основе экземпляра за экземпляром или при объявлении типа? - person The Floating Brain; 05.09.2013
comment
@IInspectable: Нет. Аргументы функции, объявленные как char const x[] и char const* x, идентичны. Однако на самом деле они различаются при использовании как typdef, но я не совсем понял, как это сделать. Вот тест: void f(char const x[], char const* y) { std::cout << std::is_same<decltype(x), decltype(y)>::value << '\n'; }. - person Dietmar Kühl; 05.09.2013
comment
Спасибо за пояснение, я неправильно истолковал char const x[] как означающий любой массив с явным размером. Без аргумента размера они действительно идентичны при использовании в качестве типов в сигнатуре функции. - person IInspectable; 05.09.2013
comment
@IInspectable: даже если вы упомянули размер в скобках, тип все равно будет char const*: то есть void f(char const x[10]) эквивалентен void f(char const* x)! Вместо 10 можно использовать любое другое положительное значение! - person Dietmar Kühl; 05.09.2013
comment
@DietmarKühl Измененный пример, чтобы продемонстрировать, что, думаю, вы имели в виду различия в определениях типов (и, как ни странно, одно и то же). Это настоящий пекарь лапши. Я думаю, что, возможно, наконец нашел свой первый вопрос SO. Спасибо. - person WhozCraig; 05.09.2013
comment
@WhozCraig: Это действительно интересный пример! Я еще не дошел до сути этого. - person Dietmar Kühl; 05.09.2013
comment
@DietmarKühl Опубликовано. У меня долгая поездка, но я зайду, когда вернусь домой. Спасибо за пищу для ума. - person WhozCraig; 05.09.2013