7 ms·
There's a big mistake here: // Bogus function, just to see how arguments are passed. void bogus(); // Invoke bogus using ptr. void do_ptr() { bogus(&p
by iainmerrick 9y ago
There's a big mistake here:
// Bogus function, just to see how arguments are passed.
void bogus();
// Invoke bogus using ptr.
void do_ptr() { bogus(&ptr, ptr); }
// Invoke bogus using arr.
void do_arr() { bogus(&arr, arr); }
"&ptr" and "&arr" are not the same. &ptr gives you a pointer to a pointer (char * *), but &arr just gives you a pointer to the array data. That's why the code is different.
This would normally show up as a compilation error, since &ptr and &arr have different types. It's disguised here by the variadic bogus() function.
(I didn't know that no-arg functions in C are implicitly variadic! That's bizarre. I would have expected modern compilers to disable that by default, but I can't get Clang to warn me about it even with -Wall.)
- 0xffff2 9y ago>(I didn't know that no-arg functions in C are implicitly variadic! That's bizarre. I would have expected modern compilers to disable that by default, but I can't get Clang to warn me about it even with -Wall.) I didn't know that either. I wonder if `void bogus(void)` behaves any differently?
- kccqzy 9y agoYes it would behave differently. Putting void in the parenthesis tells the compiler the function accepts no arguments at all.
- 0xffff2 9y agoGood to know. I never bothered with `void` inside the argument list in C before (I primarily write C++, very rarely C). I will have to remember to be more explicit when I do write C code in the future.
- Koshkin 9y agoYes, in C you must use 'void' to indicate that the function takes no arguments. (This is deprecated in C++ in favor to an empty argument list - which breaks backward compatibility with C).
- aidenn0 9y agoIt's not variadic, it's unspecified arguments. The compiler ought to complain if two function calls are made with conflicting argument types.
- a_t48 9y agoYou speak the truth! &arr is a "char (*)[12]"!
- kccqzy 9y agoIt's not really variadic in the sense that you can't use va_start and friends to access the arguments. Instead, if the actual definition doesn't match the call, it's undefined behavior and the compiler can't catch it.
- iainmerrick 9y agoUndefined behavior strikes again! It really seems like the C standard maintainers and compiler vendors should just get together and sort that whole mess out. It can give you a few extra percent in some benchmarks, sure, and help C keep its mostly-deserved reputation as the fastest language, but the cost is huge. If these non-type-checked functions are really useful in some very unusual use case, give it a special weird syntax. Don't make it the default and inflict it on everybody whether they want it or not.
- JdeBP 9y agoThey did get together to sort the mess out. They did so in the 1980s. Where do you think the idea of "ANSI function prototypes" came from?
- iainmerrick 9y agoIt's hardly a complete solution, though, since they kept the zero-arg functions around as a special case! ANSI C is the version I first learned. I didn't know that weird exception for zero-args functions still existed, or had forgotten it. I could be wrong, but I bet most C programmers don't know about it.
- Garfgon 9y agoI think it's backward compatibility, not speed. Functions with no arguments lists were supported in C89, so changing it now will break someone's code somewhere. In fact not specifying a parameter list may make your code slower, as (IIRC) default argument promotions are always applied to parameters passed to such a function.
- gumby 9y ago
- khaled 9y agoGCC has -Wstrict-prototypes.
- iainmerrick 9y agoStrange that that isn't included in -Wall! I knew -Wall isn't the same as -Weverything, but I'm always surprised at what it omits. Why wouldn't you want that warning? Edit to add: Aha, my 'gcc' was actually Clang because I'm on OS X. Installing the real GCC, I find: gcc -Wstrict-prototypes does what I want and disallows this feature. But -Wall doesn't include that flag, and GCC doesn't seem to have -Weverything. Clang accepts -Wstrict-prototypes but doesn't catch no-arg functions! That's bad. Even with -Weverything, Clang lets you do anything you want with no-arg functions. Very bad.
- khaled 9y agoI think it is not included in -Wall because such prototype are legitimate pre-ANSI K&R C function prototypes.
- iainmerrick 9y agoHmm, could be! Maybe explicitly specifying a newer standard might do the trick then. I'll try a few things.
- drt1245 9y agoAdditionally, he keeps talking about dereferencing the pointer, which I don't think is right. The pointer never gets deferenced in the code shown. I'm not an x86 guru, but I think that "movq ptr(%rip), %rsi" is different because ptr needs to be moved from relative to the instruction pointer (because it is on the stack, as a non-const variable).
- kccqzy 9y agoYou are right. This is RIP-relative addressing.
- bonzini 9y agoIt's a global variable, it's not on the stack. It's in the data section. $arr is copying the address of "arr", so it must use an immediate move (possibly 64-bit). It could also use RIP-relative with the "lea" (load effective address) instruction. $ptr(%rip) is accessing memory, so it uses RIP-relative addressing with the "mov" instruction.
- magnetic 9y ago> It's a global variable, it's not on the stack. It's in the data section. And because it's a const, it's in the .rodata section... (read-only) Playing too liberally with the data often leads to a SEGV (as it should).
- novia 9y agoThis is a little off topic, but does anyone have any good resources to help me wrap my head around pointers in C? Right now they are very confusing to me.
- Zelizz 9y agoImagine all memory is a big array. A pointer is just an index into that array. A pointer dereference is like accessing something at an array index. A pointer to a pointer is array index to a location where you'll find another array index.
- justinmk 9y ago> I didn't know that no-arg functions in C are implicitly variadic! That's bizarre. I would have expected modern compilers to disable that by default, but I can't get Clang to warn me about it even with -Wall. Try -Wstrict-prototypes, then `void` is required.
- iainmerrick 9y agoThat works in GCC, but not in Clang. As far as I can tell Clang has no warnings relating to this at all.
- eridius 9y agoBTW -Wall doesn't give you all warnings. It gives you a specific set, which will never change because of all the legacy codebases using -Wall that Clang doesn't want to cause problems with when introducing new diagnostics. The flag that really gets you all of the diagnostics is -Weverything.