Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating through a function's arguments by using a pointer to the first one

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

like image 724
Job Talle Avatar asked Jul 25 '16 10:07

Job Talle


3 Answers

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) {.

like image 72
Sourav Ghosh Avatar answered Oct 20 '22 20:10

Sourav Ghosh


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.

like image 43
Some programmer dude Avatar answered Oct 20 '22 19:10

Some programmer dude


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.)

like image 25
Bathsheba Avatar answered Oct 20 '22 20:10

Bathsheba