Я изучал соглашение о вызове x86_64, которое используется в OSX, и читал раздел «Агрегаты и союзы» в the System V x86-64 ABI standard). Он упоминает массивы, и я решил, что это похоже на массив с фиксированной длиной c, например. int[5]
.Какой тип данных C11 представляет собой массив в соответствии с AMD64 ABI
Я перешел к «3.2.3 Прохождение параметров», чтобы прочитать о том, как массивы были переданы, и если я правильно понимаю, что-то вроде uint8_t[3]
должно быть передано в регистрах, поскольку оно меньше, чем предел в четыре восемьбайт, введенный правилом 1 классификации агрегатных типов (стр. 18 у основания).
После компиляции я вижу, что вместо этого он передается как указатель. (Я компилирую с clang-703.0.31 из Xcode 7.3.1 в OSX 10.11.6).
Пример источника я использую для компиляции выглядит следующим образом:
#include <stdio.h>
#define type char
extern void doit(const type[3]);
extern void doitt(const type[5]);
extern void doittt(const type[16]);
extern void doitttt(const type[32]);
extern void doittttt(const type[40]);
int main(int argc, const char *argv[]) {
const char a[3] = { 1, 2, 3 };
const char b[5] = { 1, 2, 3, 4, 5 };
const char c[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1 };
const char d[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1 };
const char e[40] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
doit(a);
doitt(b);
doittt(c);
doitttt(d);
doittttt(e);
}
Я свалка, что в файле с именем a.c
и использовать следующую команду для компиляции: clang -c a.c -o a.o
. Я использую otool анализировать сборку генерируемый (запустив otool -tV a.o
) и получить следующий вывод:
a.o:
(__TEXT,__text) section
_main:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 leaq _main.a(%rip), %rax
000000000000000f movl %edi, -0x4(%rbp)
0000000000000012 movq %rsi, -0x10(%rbp)
0000000000000016 movq %rax, %rdi
0000000000000019 callq _doit
000000000000001e leaq _main.b(%rip), %rdi
0000000000000025 callq _doitt
000000000000002a leaq _main.c(%rip), %rdi
0000000000000031 callq _doittt
0000000000000036 leaq _main.d(%rip), %rdi
000000000000003d callq _doitttt
0000000000000042 leaq _main.e(%rip), %rdi
0000000000000049 callq _doittttt
000000000000004e xorl %eax, %eax
0000000000000050 addq $0x10, %rsp
0000000000000054 popq %rbp
0000000000000055 retq
Или то же самое, здесь он находится на Godbolt compiler explorer with clang3.7, которая ориентирована на Linux, которая использует тот же ABI.
Итак, мне было интересно, может ли кто-нибудь привести меня к тем, какие типы данных в C11 относятся к массивам. (Похоже, что clang по умолчанию использует C11 - см. Расписание here прямо под встроенной функцией C99).
Я также провел аналогичное исследование с ARM и нашел аналогичные результаты, хотя ARM standard также указывает, что существует массив агрегатного типа.
Кроме того, существует ли где-то в каком-то стандарте, что указано, что массив с фиксированной длиной должен рассматриваться как указатель?
@PeterCordes: Массивы распадаются на указатели в большинстве, но не во всех контекстах. Более того, C не разрешает параметры типа массива. В объявлении типа 'void func (int param []);', тип 'param' ** корректируется ** из' int [] 'в' int * '. (Это отличное правило от того, которое указывает неявное преобразование выражений массива в указатели.) –
@PeterCordes, так нет ли типа данных в c11 или c99, который считается массивом, как определено в стандартах x86_64/arm? – DanZimm
@KeithThompson У вас есть ссылка на то, что C не разрешает параметры типа массива? Я бы хотел больше узнать! – DanZimm