Добавление ключевого слова 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, которые зависят от свойств в контейнере.