------- Comment #14 from rogerio at rilhas dot com 2010-08-11 11:22 ------- No, you are not correct. The equivalent code to what I'm doing would be something like:
int buffer[4]; // 16 bytes on stack buffer[0]=(int)&format buffer[1]=(int)10 buffer[2]=(int)&another_string buffer[3]=(int)20 call format_direct format_direct: char** PTR4=(char**)&buffer[0]; push PTR4 call format_indirect format_indirect: char** PTR4=get_from_stack // gets PTR4 as pushed in format_direct printf("%s %d %s %d", PTR4[0], // the same as (char*)buffer[0] PTR4[1], // the same as (int)buffer[1] PTR4[2], // the same as (char*)buffer[2] PTR4[3] // the same as (int)buffer[3] ); This code must work, obviously. There is no undefined behaviour, it is correct and portable code, and well defined and established. Even if the machine is 16 bits this would work without changes, just replace comment "16 bytes" by "8 bytes" and name PTR4 to PTR2, if you like the cosmetic changes. I understand that when you look at your code you would call it undefined behaviour, but your code is not the correct one: this one is. That is what I've been trying to explain. The calling convention states that the parameters should be packed ajdacent, like I did in the struct above, and not as you did in your example, and getting the address of the parameter should get the address of the start of the buffer, as I did manually. Your code just ignored this and, of course, would not work (you don't even say where you think the other parameters are). This is not an invention of mine, or something that only works when I'm lucky, packing all parameters adjacent to each other is something the compiler really needs to do, so if it gives me the correct address of the first parameter then this code works *always* and is very portable. To show you that you are not correct I've done some changes to the source file, where I created a new function "format_direct2" that does something like this: void format_direct2(char* dst_buffer, int dst_buffer_size_bytes, const char* format, ...) { int buffer[3]; buffer[0]=(int)format; buffer[1]=(int)__DATE__; buffer[2]=(int)__TIME__; format_indirect(dst_buffer, dst_buffer_size_bytes, (const char**)&buffer[0]); } The new code works always, of course, since I'm the one ensuring that the parameters are adjacent, and I'm the one selecting the correct address to pass to "format_indirect". I am, in fact, manually generating the 2 requirements - compliance with the calling convention and passing the correct address to "format_indirect". It also works with GCC, of course, even when optimized (as expected) and I attach the corresponding files. So, when optimized, you get "format_direct2" to work correctly and "format_direct" causes a segmentation fault (and it shouldn't). It would sure be interesting to see if you could quote some standard for C which says that I'm not allowed to do this!!! I simply don't believe you can find such text, or have I been wrong about C all my life and I can't use pointers to navigate through buffers?? :-) -- rogerio at rilhas dot com changed: What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |UNCONFIRMED Resolution|INVALID | http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45249