Я помню пример, где была продемонстрирована разница между указателями и массивами.
Массив распадается на указатель на первый элемент в массиве при передаче в качестве параметра функции, но они не эквивалентны, как показано ниже:
//file file1.c
int a[2] = {800, 801};
int b[2] = {100, 101};
//file file2.c
extern int a[2];
// here b is declared as pointer,
// although the external unit defines it as an array
extern int *b;
int main() {
int x1, x2;
x1 = a[1]; // ok
x2 = b[1]; // crash at runtime
return 0;
}
Компилятор не проверяет тип для внешних переменных, поэтому во время компиляции не генерируются ошибки. Проблема в том, что b
на самом деле является массивом, но блок компиляции file2
не знает об этом и рассматривает b
как указатель, что приводит к сбою при попытке разыменовать его.
Я помню, когда это объяснялось, это имело смысл, но теперь я не могу вспомнить объяснение, и я не могу придумать это сам.
Итак, я думаю, вопрос в том, как массив обрабатывается иначе, чем указатель при доступе к элементам? (потому что я думал, что p[1]
преобразуется в (эквивалент сборки) *(p + 1)
, независимо от того, является ли p
массивом или указателем - я, очевидно, ошибаюсь).
Сборка, сгенерированная двумя разборами (VS 2013):
примечание: 1158000h
и 1158008h
- адреса памяти a
и b
соответственно
12: x1 = a[1];
0115139E mov eax,4
011513A3 shl eax,0
011513A6 mov ecx,dword ptr [eax+1158000h]
011513AC mov dword ptr [x1],ecx
13: x2 = b[1];
011513AF mov eax,4
011513B4 shl eax,0
011513B7 mov ecx,dword ptr ds:[1158008h]
011513BD mov edx,dword ptr [ecx+eax]
011513C0 mov dword ptr [x2],edx