#c #c #arrays #null
#c #c #массивы #null
Вопрос:
void DoSomeThing(CHAR parm[])
{
}
int main()
{
DoSomeThing(NULL);
}
Разрешена ли передача NULL для параметра массива в C / C ?
Комментарии:
1. @VladLazarenko: Я думаю, вы пропустили различие между «возможным» и «разрешенным»
2. «Попробуйте» — хороший первый шаг, но особенно в области C и C с их сотнями языковых расширений, зависящих от компилятора, тот, кто хочет переносимости, должен спросить юристов по языку. Не то, чтобы это был особенно важный вопрос.
3. @reader: Нет, именно поэтому у нас есть спецификации . То, что он компилируется, не означает, что это разрешено.
4. @JohnDibling — И только потому, что это разрешено, не означает, что оно компилируется.
5. @JohnDibling Я думаю, что компиляторы разрешают или отклоняют вещи, спецификации говорят, как все должно быть. Вы не можете скомпилировать программу со спецификацией. Если бы вопрос был в том, является ли допустимым использование, мы бы обязательно посмотрели на спецификацию. Посмотрите на этот пост: списки. whatwg.org/pipermail/whatwg-whatwg.org/2009-June/… Разработчик спецификации обновил спецификацию, потому что, хотя все должно быть в соответствии со спецификациями, но в реальном мире это не так.
Ответ №1:
Чего вы не можете сделать, так это передать массив по значению. Сигнатура функции
void f( char array[] );
преобразуется в:
void f( char *array );
и вы всегда можете передать NULL в качестве аргумента функции, принимающей указатель.
Однако вы можете передать массив по ссылке в C , и в этом случае вы не сможете передать нулевой указатель (или любой другой указатель):
void g( char (amp;array)[ 10 ] );
Обратите внимание, что размер массива является частью типа и, следовательно, частью подписи, что означает, что g
будут приниматься только выражения типа lvalue типа array из 10 символов
Ответ №2:
Короткий ответ: да, вы можете передать NULL в этом экземпляре (по крайней мере, для C, и я думаю, что то же самое верно и для C ).
Для этого есть две причины. Во-первых, в контексте объявления параметра функции объявления T a[]
и T a[N]
являются синонимами T *a
; IOW , несмотря на обозначение массива, a
объявляется как указатель на T
, а не как массив T
. Из стандарта языка Си:
6.7.5.3 Деклараторы функций (включая прототипы)
…
7 Объявление параметра как ‘массива типа’ должно быть скорректировано на ‘квалифицированный указатель на тип’, где квалификаторы типа (если таковые имеются) являются теми, которые указаны в[
и]
производной типа массива. Если ключевоеstatic
слово также появляется в[
и]
производной типа массива, то для каждого вызова функции значение соответствующего фактического аргумента должно предоставлять доступ к первому элементу массива, содержащего по меньшей мере столько элементов, сколько указано в выражении size .
Вторая причина заключается в том, что когда выражение типа array появляется в большинстве контекстов (например, при вызове функции), тип этого выражения неявно преобразуется («распадается») в тип указателя, поэтому фактически функции передается значение указателя, а не массив:
6.3.2.1 Значения Lvalues, массивы и обозначения функций
…
3 За исключением случаев, когда это операндsizeof
оператора или унарногоamp;
оператора или строковый литерал, используемый для инициализации массива, выражение, имеющее тип ‘массив типа’, преобразуется в выражение с типом ‘указатель на тип’, который указывает на начальный элемент объекта массива ине является значением lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.
Ответ №3:
Во-первых, то, что вы передаете функции, является указателем, а не массивом. Обозначение массива, используемое для parm
параметра, является просто синтаксическим сахаром для CHAR *parm
.
Так что да, вы можете передать NULL
указатель.
Ответ №4:
Единственной проблемой было бы, если бы doSomething был перегружен, и в этом случае компилятор мог бы не различить, какую функцию вызывать. Но приведение к соответствующему типу теоретически исправило бы это.