Я знаю, что следующие определения функций считаются одинаковыми компилятором c
void test(int* array); // all converted to first one
void test(int array[]);
void test(int array[3]);
и в стандарте C99
За исключением случаев, когда это операнд оператора sizeof или унарного & оператор или строковый литерал, используемый для инициализации массива, выражение, имеющее тип «массив типов», преобразуется в выражение с типом «указатель на тип», который указывает на начальный элемент объекта массива и не является lvalue. Если объект массива имеет класс хранения регистра, поведение не определено.
мои вопросы после того, как int array[]
распадается на указатель, тогда это также lvalue как локальная переменная в вызове функции, нарушает ли это стандарт, согласно которому преобразованный указатель не должен быть lvalue?
Привет @Barmar, хороший улов, ты случайно не знаешь, где в стандарте я могу найти правило преобразования объявлений? Спасибо
См. C99 6.7.5.3 параграф 7.
Это не проблема, так как здесь есть две вещи: настройка параметров массива на указатели и то, как устанавливаются параметры функции.
Эквивалентность трех объявлений, которые вы дали, прописана в разделе 6.7.6.3p7 стандарта C:
Объявление параметра как «массива типа» должно быть скорректировано для ‘‘квалифицированный указатель на тип’’, где квалификаторы типа (если есть) те, которые указаны в
[
и]
производного типа массива. Если ключевое слово static также появляется в[
и]
типа массива вывод, то для каждого вызова функции значение соответствующий фактический аргумент должен обеспечивать доступ к первому элемент массива, содержащий как минимум столько элементов, сколько указано в выражение размера
Таким образом, это означает, что во всех вышеперечисленных случаях тип параметра array
— int *
.
Затем, как параметры заполняются. Это указано в 6.5.2.2p4 относительно вызовов функций:
Аргумент может быть выражением любого полного типа объекта. В подготовка к вызову функции, оцениваются аргументы и каждому параметру присваивается значение соответствующего аргумента
Итак, учитывая следующее:
int a[5];
test(a);
Внутри есть присваивание, то есть array = a
от переданного значения параметра к фактическому параметру функции.
мои вопросы после того, как int array[] распадается на указатель, тогда это также lvalue как локальная переменная в вызове функции, нарушает ли она стандарт, что преобразованный указатель не должен быть lvalue?
Кавычка означает, что после неявного преобразования массива в указатель на его первый элемент указатель не является lavlue. Например, компилятор выдаст ошибку, если вы напишете например
int a[10];
++a;
В этом выражении ++a
указатель массива a
неявно преобразуется в указатель на его первый элемент, но указатель не является lvalue. Вы не можете увеличить его. Если бы вы написали вместо
int a[10];
int *p = a;
++p;
тогда выражение ++p
верно, потому что p
является lvalue.
Что касается такой функции
void test(int array[]);
затем переданный массив преобразуется в указатель на его первый элемент, и указатель не является lvalue. Но указатель используется для инициализации параметра функции, который подгоняется компилятором к типу int *. И, конечно же, параметр является lvalue внутри функции.
Точно так же, если у вас есть функция, которая возвращает массив, который преобразуется в указатель на его первый элемент, например,
int * test( void )
{
static int a[10];
return a;
}
затем снова возвращаемый указатель не является lvalue. Например, вы не можете писать
printf( "%p\n", ( void * )++test() );
То есть вы не можете увеличивать возвращаемый указатель.
Цитата касается выражений, а не объявлений. В объявлениях параметров нет «распада», все они просто эквивалентны объявлениям указателей.