Добавление ключевого слова const в массив, переданный как параметр для функции

Можно ли добавить ключевое слово const в массив, переданный в качестве параметра для функции:

void foo(char arr_arg[])

Если я помещаю const до char (void foo(const char arr_arg[])) или после char (void foo(char const arr_arg[])), это будет означать, что он char, который является константой, а не arr_arg.

Я просто читал, что под капотом массив, отправленный как параметр функции, представляется как указатель, поэтому void foo(char arr_arg[]) - это так же, как void foo(char* ptr_arg). Принимая это во внимание, я могу переписать функцию как void foo(char * const ptr_arg), чтобы это было именно то, что я хочу достичь.

Но я хочу знать, есть ли способ добавить ключевое слово const в это объявление void foo(char arr_arg[]), чтобы оно было таким же, как void foo(char * const ptr_arg) не void foo(char const * ptr_arg) или void foo(const char * ptr_arg))?

Я просто хочу понять, есть ли синтаксис для создания константы arr_arg с записью массива [].

Ответы

Ответ 1

В C вы должны поместить const между [], каким бы странным это ни казалось, чтобы выглядеть неподготовленным человеком

void foo(char arr_arg[const]);

Это "новый" Синтаксис, специфичный для C99. В C89/90 или С++ нет способа сделать это с помощью синтаксиса "array", поэтому вам нужно переключиться на эквивалентный синтаксис "указатель", как это было предложено в ответе Дэвида.

Ответ 2

Прежде всего, в вашей конкретной сигнатуре аргумент преобразуется компилятором в указатель, поэтому у вас есть:

void foo( char * arg );

Теперь есть две сущности, которые могут быть сделаны в этой сигнатуре: указатель и заостренный тип. Чтобы сделать точечный тип, можно сделать const двумя разными, но эквивалентными способами [*]:

void foo( const char * arg );
void foo( char const * arg );

Указатель может быть const с синтаксисом:

void foo( char * const arg );

Но обратите внимание, что в сигнатуре функции, так же, как char arg[] преобразуется в указатель char *arg, квалификатор верхнего уровня отбрасывается. Таким образом, с точки зрения декларации эти два эквивалента:

void foo( char * const arg );
void foo( char *       arg );

В определении верхний уровень const может использоваться для указания компилятору, что указатель аргумента (по значению) не должен быть изменен внутри функции, и он обнаружит, если вы попытаетесь reset указатель на другой место нахождения. Но если только указатель const, то компилятор с радостью позволит вам изменить указанную память. Если вы не хотите, чтобы функция меняла содержимое массива, вы должны выбрать одну из первых двух подписей.

[*] Я предпочитаю формат char const *, поскольку он обеспечивает последовательный способ чтения типов: справа налево он читает: указатель не const const на const char. Кроме того, проще определить типы typedef-ed (путем прямой подстановки в выражении). Учитывая typedef char* char_p;, const char_p и char_p const оба эквивалентны char * const и отличаются от const char *. Путем последовательного использования const справа вы можете просто вслепую подменить typedef и прочитать тип без объяснения причин.

Ответ 3

Да, в C это возможно, так как C99:

void foo(char ptr_arg[const]);

является допустимым синтаксисом и эквивалентным

void foo(char *const ptr_arg);

В общем случае [] может содержать квалификатор любого типа, static и целочисленное выражение. Но

Необязательные классификаторы типов и ключевое слово static должны появиться только в объявлении параметра функции с типом массива, а затем только в самом внешнем выводе типа массива.

то есть для измерения, эквивалентного объявлению указателя.

Ответ 4

В С++ существует несколько способов, но ни один из них не выглядит так, как вы ожидаете.

//typedef has a very clear intent
typedef char* array;
void f0(const array a) {}

//switch to pointers to sidestep the problem
void f1(char* const a) {}

//references are inherently const
//can't take pointers, but guarantees the size, sometimes nice
//this version obviously doesn't work in C
template<int n>
void f2(char (&a)[n]) {}

http://ideone.com/4LvYT

Ответ 5

Для С++ ответ Mooing Duck с использованием шаблона является самым прямым.

Если у вас есть C-код, вызывающий интерфейс C, реализованный на С++, вы застряли в преобразовании аргумента в аргумент указателя вместо этого и создаете const

Если бы вы использовали Boost array вместо непосредственного использования массивов C, то вы могли бы сделать это const, хотя это также будет функцией шаблона:

template <unsigned N>
void foo (Boost::array<char, N> const & arg) {}

Преимущество Boost::array заключается в том, что он дает вам возможность выполнять легкое выделение массива из стека, но может полностью использовать алгоритмы STL, которые зависят от свойств в контейнере.