There is no information about the function's prototype in the object file, so the linker can't determine that. The compiler can't either since it's just compiling the compilation unit and has no knowledge of the outside world except what we tell it by prototypes (injected via header files or otherwise), but we aren't doing that here.
Includes don't control linking, and traditional C did not require function prototypes, so most compilers (in non-C++ mode at least) will happily compile calls to unknown functions, it just assumes a default signature.
Yeah. If you don't include the header from the source file you will inevitably end up with differing function signatures in the header and source files because the compiler won't be able to compare the declaration and definition to each other. Such a program may even link.
That requirement vhas been gone for decades if it ever existed, though static library semantics look a bit like that if you don't pass extra flags around them.
Linkers are multiple pass if doing compiler optimisation things. Otherwise they're pretty close to cat + patch some pieces, single pass seems fair.
It's not immediately obvious to me why linkers don't say which functions were making the undefined symbol call. A suspicion is that the linker may not know what the function name is for the corresponding instruction without digging it out of the debug info and the linker probably doesn't have the corresponding parser ready to hand. It probably could narrow it down to a source object file, though libraries make that difficult.
In other words, the compiler can infer this from the function definition (or at least clang does), but it cannot infer this from a function declaration, because the implementation is missing - unless you are using LTO like the parent mentions.
The compiler tends to be limited in how it can change calling conventions by external visibility of the functions. Generally if you compile a function down to an object file the compiler will want to make that object file linkable with any other object files importing that symbol properly.
Whole program optimization gives the compiler some ways around that. I am not sure how much freedom it gives the compiler.
How do you know it's never called? You can call the function from another file. It's not possible to know that the function is never called until link time.
My understanding is that, unless you have a function prototype, you will lose type info about the parameters:
"The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied."
i.e. the most important is the end of that sentence, so GCC behavior should be right.
no they are not.
but
>The fact that I'm calling a function, it must exist, otherwise the compiler will throw an error ("undefined reference to function")
you mean the linker will throw an error. The linker is trying to link together the "references" be they forward or backward, that the compiler has created, and the compiler needs to have generated the right references, round peg round hole, square peg square hole.
You don't want your linker throwing errors, it doesn't have the context the compiler does; and you don't want to turn the linker into ChatGPT that can converse with you about your source code, just use the C version of forward references which are not particularly forward, they just say "I don't know where this is defined, it's just not defined here, but we know it's a square peg"
For example, there are architectures where space is tight (embedded for example) and nearby things can be called more efficiently than far away things, so the compiler needs to generate as many near calls as it can, falling back to far away when it has to. It doesn't know in advance how far away things are going to be, but it might uncover plenty of near things as it goes. Square pegs, round pegs.
when you recompile your project code, the library code, is not necessarily around. When other people recompile their library code, your project code isn't around. What's the size of what's being put on the stack? Still gotta get the square/round pegs right.
The function is declared/defined/described/written once, and used once. There is no ambiguity.
I don't understand your point about using a function that hasn't been declared. Of course it won't work!
I understand your point about using header files as interfaces to third-party code, but there are ways of doing that that don't involve duplicating all functions, structs etc.
And this is where Delphi's smart linker is smart: it's always using function-level linking.
(I can't answer your question in detail because it's been a long time since I've been poking around in object files and I don't know what C/C++ compilers and linkers have been doing with them recently. I was a compiler engineer at Borland for more than 5 years, but it was years ago.)
I'm the author but I'll chime in and say that yes, linker ordering is undefined (or at least only partially defined) in general, and definitely in this case.
The C++ language says that the linker is free to choose any instantiation of an inline function because they are required to be identical. Failure to make them identical is an ODR violation, and the ODR implicitly says that the linker can grab whichever one it wants.
It's in a lot of ways more about not being defined (but possibly declared) yet, rather than initialized. You'd be super sad if you could not reference a function defined later in a source file.
reply