В чем разница между двумя функциями в C?
void f1(double a[]) {
//...
}
void f2(double *a) {
//...
}
Если бы я вызвал функции из очень длинного массива, разве бы эти две функции вели себя по-разному, занимали бы они больше места в стеке?
В чем разница между двумя функциями в C?
void f1(double a[]) {
//...
}
void f2(double *a) {
//...
}
Если бы я вызвал функции из очень длинного массива, разве бы эти две функции вели себя по-разному, занимали бы они больше места в стеке?
Ответы:
Во-первых, несколько стандартных :
6.7.5.3 Деклараторы функций (включая прототипы)
...
7 Объявление параметра как '' массив типа '' должно быть скорректировано как '' квалифицированный указатель на тип '', где квалификаторы типа (если есть) являются теми, которые указаны внутри[
и]
производного типа массива. Если ключевое словоstatic
также появляется внутри[
и]
в производном типе массива, то для каждого вызова функции значение соответствующего фактического аргумента должно обеспечивать доступ к первому элементу массива с по крайней мере таким количеством элементов, как указано размером. выражение.
Короче говоря, любой параметр функции, объявленный как T a[]
или T a[N]
, обрабатывается так, как если бы он был объявлен T *a
.
Итак, почему параметры массива обрабатываются так, как будто они были объявлены как указатели? Вот почему:
6.3.2.1 Значения L, массивы и указатели функций
...
3 За исключением случаев, когда это операндsizeof
оператора или унарный&
оператор, или строковый литерал, используемый для инициализации массива, выражение, имеющее тип "массив типа " 'преобразуется в выражение с типом' 'указатель на тип ' ', которое указывает на начальный элемент объекта массива и не является lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.
Учитывая следующий код:
int main(void)
{
int arr[10];
foo(arr);
...
}
При вызове foo
выражение массива arr
не является операндом для sizeof
или &
, поэтому его тип неявно преобразуется из «10-элементного массива int
» в «указатель на int
» в соответствии с 6.2.3.1/3. Таким образом, foo
будет получено значение указателя, а не значение массива.
Из-за 6.7.5.3/7 вы можете писать foo
как
void foo(int a[]) // or int a[10]
{
...
}
но это будет интерпретироваться как
void foo(int *a)
{
...
}
Таким образом, две формы идентичны.
Последнее предложение в 6.7.5.3/7 было введено с C99 и в основном означает, что если у вас есть объявление параметра, например
void foo(int a[static 10])
{
...
}
фактический параметр, соответствующий, a
должен быть массивом не менее чем из 10 элементов.
Разница чисто синтаксическая. В C, когда для параметра функции используется запись массива, она автоматически преобразуется в объявление указателя.
Нет, никакой разницы между ними нет. Для тестирования я написал этот код C в компиляторе Dev C ++ (mingw):
#include <stdio.h>
void function(int* array) {
int a =5;
}
void main() {
int array[]={2,4};
function(array);
getch();
}
Когда я разбираю основную функцию в .exe обеих вызывающих версий двоичного файла в IDA, я получаю точно такой же код сборки, как показано ниже:
push ebp
mov ebp, esp
sub esp, 18h
and esp, 0FFFFFFF0h
mov eax, 0
add eax, 0Fh
add eax, 0Fh
shr eax, 4
shl eax, 4
mov [ebp+var_C], eax
mov eax, [ebp+var_C]
call sub_401730
call sub_4013D0
mov [ebp+var_8], 2
mov [ebp+var_4], 4
lea eax, [ebp+var_8]
mov [esp+18h+var_18], eax
call sub_401290
call _getch
leave
retn
Таким образом, нет никакой разницы между двумя версиями этого вызова, по крайней мере, компилятор угрожает им одинаково.