I would like to know whether the following C code adheres to the C99 and/or C11 standard(s):
void foo(int bar0, int bar1, int bar2) {
int *bars = &bar0;
printf("0: %d\n1: %d\n2: %d\n", bars[0], bars[1], bars[2]);
}
int main(int argc, char **argv) {
foo(8, 32, 4);
return 0;
}
This code snippet compiles and runs as expected when using visual studio 2013 and prints:
0: 8
1: 32
2: 4
No, not anywhere near.
C standard does not guarantee that the function arguments are stored in consecutive memory locations (or, any specific ordering, for that matter). It is up to the compiler and/or the platform (architecture) to decide how the function arguments are passed to the function.
To add some more clarity, there is even no guarantee that the arguments which are to be passed are stored in memory (e.g., stack), at all. They can make use of the hardware registers, too (whenever applicable), for some or all the parameters, to make the operations fast. For example,
PowerPC
The PowerPC architecture has a large number of registers so most functions can pass all arguments in registers for single level calls. [...]
MIPS
The most commonly used calling convention for 32 bit MIPS is the O32 ABI which passes the first four arguments to a function in the registers
$a0
-$a3
; subsequent arguments are passed on the stack. [...]
X86
The x86 architecture is used with many different calling conventions. Due to the small number of architectural registers, the x86 calling conventions mostly pass arguments on the stack, while the return value (or a pointer to it) is passed in a register.
and so on. Check the full wiki article here.
So, in your case, bars[0]
is a valid access, but whether bars[1]
and bars[2]
are valid, depends on the underlying environment (platform/compiler), entirely. Best not to rely on the behavior you're expecting.
That said, just to nitpick, in case you don't intend to use the arguments (if any) passed to main()
, you can simply reduce the signature to int main(void) {
.
No it does not adhere to any published standard. How arguments and local variables are stored, and where, is up to the compiler. What might work in one compiler might not work in another, or even on a different version of the same compiler.
The C specification doesn't even mention a stack, all it specifies are the scoping rules.
No standard supports this. It's extremely naughty.
Array indexing and pointer arithmetic is only valid for arrays. (Note a small exception: you can read a pointer one past an array or a scalar, but you can't deference it.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With