Base arrays as functions of args in C and C ++ always break into pointers, as in other contexts.
Arrays inside a struct or union not executed and passed by value. This is why ABIs need to take care of how they are passed, although this does not happen in C for bare arrays.
As Keith Thomson points out , the relevant part of standard C N1570 section 6.7.6.3 clause 7
Declaring a parameter as a "type array" should be adjusted to a "qualified type pointer", where type qualifiers (if any) are those specified in the [and] array type output ... (for material on foo[static 10] , see below)
Note that multidimensional arrays work like arrays of type array, so only the outer level of "array-ness" is converted to a pointer to the type of array.
Terminology: The x86-64 ABI document uses the same terms as ARM, where struct and arrays are “aggregates” (multiple elements at consecutive addresses). Thus, the phrase “aggregates and unions” arises a lot because union processed in a similar way to the language and ABI.
This is a recursive rule for handling composite types (struct / union / class), which results in game rules that pass an array to ABI. This is the only way to see asm that copies the array onto the stack as part of the arg function, for C or C ++
struct s { int a[8]; }; void ext(struct s byval); void foo() { struct s tmp = {{0}}; ext(tmp); }
gcc6.1 compiles it (for AMD64 SysV ABI with -O3 ) into the following:
sub rsp, 40
In ABI x86-64, the pass-by-value occurs by actually copying (to registers or the stack), and not using hidden pointers.
Note that return-by-value passes the pointer as the “hidden” first arg (in rdi ) when the return value is too large to match the 128-bit concatenation of rdx:rax (and there is no vector returned in vector regs, etc. d.).
It would be possible for the ABI to use a hidden pointer to objects with a value greater than a certain size and trust the function to be called not to change the original, but this is not what the x86-64 ABI chooses, It would be better in some cases (especially for inefficient C ++ with a lot of copying without changes (i.e., wasted)), but worse in other cases.
Read SysV ABI Bonus . clang / gcc sign / zero extend narrow arguments up to 32 bits .
Note that in order to truly ensure that the arg function is a fixed-size array, C99 and later allows you to use the static in a new way : array sizes. (It is still passed as a pointer, this does not change the ABI).
void bar(int arr[static 10]);
This allows sizeof(arr) to work as you would expect inside the called function, and allow compiler warnings about going out of bounds. It also potentially provides better optimization if the compiler knows that it allows access to elements that are not in source C. (See this blog post ).
The same keyword page for C ++ states that the C ++ ISO does not support this use of static ; this is one of those C-only functions, along with C99 variable-length arrays and several other goodies that C ++ does not have.
In C ++, you can use std::array<int,10> to get the compilation time size information passed to the caller. However, you need to manually pass it by reference if this is what you want, since it is, of course, just a class containing int arr[10] . Unlike a C-style array, it does not decompose into T* automatically.
The ARM document that you linked does not seem to call arrays the aggregate type: Section 4.3, “Composite Types” (which discusses alignment) distinguishes arrays from aggregate types, although they appear to be a special case of its definition for aggregates.
A Composite Type is a collection of one or more basic data types that are processed as a unit at the procedure call level. The composite type can be any:
- An assembly in which elements are sequentially placed in memory
- An association where each member has the same address
- An array that is a repeated sequence of another type (its base type).
Definitions are recursive; that is, each of the types may contain a composite type as a member
“Composite” is an umbrella term that includes arrays, structures, and associations.