4 ms·
> You could put a function's definition in every source file that needs it but that's a terrible idea since the definition has to be the same everywhere if you
by wahern 8y ago
> You could put a function's definition in every source file that needs it but that's a terrible idea since the definition has to be the same everywhere if you want anything to work. Instead of having the same definition everywhere, we put the definition in a common file and include it where it is necessary. This common file is what we known as a header.
In C and C++ parlance "definition" should be "declaration" and "implementation" should be "definition".[1] The terminology is important if you don't want to get confused when learning more about C and C++. This is compounded by the fact that some languages describe these roles in the author's original terms. (Perhaps the author's terminology reflects his own confusion in this regard?)
[1] This is indisputable given the surrounding context, but I didn't want to paste 3-4 whole paragraphs.
- deleted 8y ago[deleted]
- kccqzy 8y agoYes, indeed. In extremely old code, I sometimes see people preferring to manually write declarations of functions (even libc functions) in every source file instead of including a header. To add to the confusion, in certain cases, it is possible to put a function's definition in a header file (for example if it's a function template, or in an anonymous namespace, or the static keyword is used to indicate internal linkage). So it is possibly to write this function definition manually in every translation unit. Otherwise, the ODR rule requires functions to be defined exactly once. > One and only one definition of every non-inline function or variable that is odr-used is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.
- quietbritishjim 8y agoInterestingly a form the "one definition rule" even applies to some of those functions that can appear in multiple translation units, specifically inline functions and template functions (not static functions or those in an unnamed namespace). In those case it says that they must be identical in all the translation units that they're defined in, so it's more like a "unique definition rule" for them. This sounds like it would be easy – just put the definition a header file. But even if the text of a function is identical in different translation units, it can still be ODR-different between them if the symbols that they look up are different due to other header files included before them declaring different thing or doing things like "using namespace std". Argument-dependent lookup is especially dangerous here. As with other ODR violations, this causes undefined behaviour and compilers/linkers aren't required to issue a diagnostic (and they usually don't!). I believe C++20 modules will solve this problem.
- jcelerier 8y ago> this causes undefined behaviour and compilers/linkers aren't required to issue a diagnostic (and they usually don't!) -fsanitize=undefined with LTO has shown ODR violations for a long time
- gpderetta 8y ago> even if the text of a function is identical in different translation units, it can still be ODR-different between them if the symbols that they look up are different due to other header files included before them declaring different thing Exactly. This is why you should never put anonymous namespaces and definitions of objects with static linkage in an header file.
- alexhutcheson 8y agoThe functions can also be different if different compilation units were compiled using different compiler settings (or event different compilers). In Titus Winters' recent Pacific++ talk[1], he pointed out that even something as simple as including an 'assert' statement will violate the ODR if some compilation units are compiled with 'debug' settings and some aren't. This can easily happen with build systems that cache compiled object files if changes in compilations flags don't automatically invalidate the cache. [1] https://youtu.be/IY8tHh2LSX4?t=900 https://youtu.be/IY8tHh2LSX4?t=900
- cm2187 8y agoAs a non c++ programmer, what I don't understand is why do people need to write header files by hand. Surely it should be auto-generated from the source code?
- berti 8y agoHeaders are used control visibility of declarations (note though that visibility of symbols themselves is controlled by other means), and typically contain more than just function declarations (structs, enums, etc.). There are basically two common patterns to split public and private declarations: - public header for consumers of the interface, private header for internal use only - public header for consumers, private declarations directly in the .cpp/.c file
- MaxBarraclough 8y agoHeader-generator tools are out there, but I'm not sure how usable they are. It's rarely done though. It's a bit of a pain having to 'write everything twice', but there's more to header files than re-declaring what you've done in your source files. As berti said: enums, constants, macros, simple struct type declarations, typedefs, and templates, are examples of hand-written code that might belong entirely in the header file. It would be possible to keep these constructs in a hand-written header file while auto-generating the rest, but C++ developers aren't convinced this is worth doing.
- bluGill 8y agoRemember you are writing your comment in 2018, what was feasible in 1975 was very different. Programmers back then were smart enough to pull the job off, but the computers they had were limited such that it wasn't worth it. First because the computers were limited programs had to be smaller so the benefit wasn't as great. Second computers were slower so it was worth spending extra human effort once to save a lot of computer effort. C++ has been working on modules to fix this for years now. It turns out to be harder than you would think. Everyone agrees with the basic problems statement, but there is disagreement on the details. All sides have good points in favor of their approach, and there are some places where you have both as they are incompatible. Progress is being made (and a lot of the incompatibilities turned out to be solvable but it took years of thinking to come up with how)
- green7ea 8y agoThank you for the correction, you are entirely correct and it is a big oversight on my part. I tried to use as few technical terms as possible to make the article more approachable but ended up doing something worse: I misused a technical term which is misleading. I will correct this as soon as I have some time to do so.
- bun_at_work 8y agoThanks for the write-up and the effort to fix mistakes. Great stuff.