Does a function in the standard library override one definition rule?

#include <cmath> double log(double) {return 1.0;} int main() { log(1.0); } 

Suppose that the log() function in <cmath> declared in the global namespace (this is not actually indicated, and we just make this assumption), then it refers to the same function as the log() function that we defined . <w> Thus, this code violates the rule with one definition (see here , since no diagnostics are required, this code can be compiled in the compiler, and we cannot say if this is correct)?

Note After recent changes, this is not a duplicate: What is one definition rule in C ++?

+4
c ++ standards c ++ - standard-library one-definition-rule c-standard-library
Jan 16 '17 at 6:44
source share
3 answers

A typical scenario.

If extern "C" double log(double) initially declared in the global namespace, then you updated it and provided a definition. The previous mention of extern "C" made during implementation is carried over to your corresponding declaration. Your definition refers to a function belonging to the implementation, and this is an ODR violation.

Regarding the manifestation of UB: it seems to usually refer to log as a symbol of a weak linker. Your implementation overrides libc.so according to ABI rules.

(If the implementation does not execute extern "C" , it is still basically all the same.)

Another likely scenario.

If log declared in namespace std and then entered into the global namespace, your declaration will conflict with it. (Actually, the using declaration is a technical declaration.) This error is diagnosed.

Estimated scenario.

then this refers to the same function as the log function that we defined

One way to implement the insertion of the <cmath> names in the global namespace is to declare the extern "C" function inside the namespace std , then do using namespace std and make sure that this always happens as the first when the standard header is included. Since using namespace not sticky — it applies only to previous declarations in the item namespace — the rest of the standard library will not be visible. (This will not declare names in the global namespace, but the standard only says “fits in the global namespace”.)

In this implementation, your declaration will hide the standard one and declare a new function with a new changed name (say _Z3logd instead of a simple log ) and a new fully qualified name ( ::log instead of ::std::log ). Then there would be no violation of ODR (if some built-in function does not use one log in one TU and another in another TU).

+3
Jan 16 '17 at 8:39 on
source share

The following addresses precede the OP revision. I leave it here if future readers come here with a similar request.

I suppose that two names refer to the same object if and only if they have the same declarative region, where the concept of “declarative region” is defined in the standard [...] Is this assumption correct? Are there any words in the standard that support this?

He called the variable hiding or shading colloquially. And the standard says what you said almost verbatim. §3.3.10 ¶1 in the current standard draft C ++ 17:

A name can be hidden by explicitly declaring the same name in a nested declarative scope or derived class




Does this code also violate the rule with one definition (see here, since no diagnostics are required, this code can be compiled in some kind of compiler, and we cannot say that this is correct)?

I will not expect this. The standard requires that all cheader headers (and in particular cmath ) enter their characters in the std . The implementation, which also injects it into the global namespace, matches the standard (since the standard leaves this bit as unspecified), but I would find it in a bad way. You are right that this can happen. Now, if you include math.h (against the advice of the sages), this will certainly violate one definition rule.

+3
Jan 16 '17 at 6:48
source share

Caution. ODR applies only to definitions that will be included in the final program. This means that this does not apply to characters that may be present in libraries, because the (normal) linker does not load entire libraries, but only those parts that are necessary for character resolution. For example, in this code:

 #include <cmath> double log(double) {return 1.0;} int main() { log(1.0); } 

No ODR violations:

  • either the log symbol from the standard C library was included only in the std , and there were no collisions at all
  • or is it also included in the global namespace

In the latter case, the double log(double) declaration does not conflict with that of cmath, because it is the same. And since the log symbol is already defined, its definition from the standard library will not be included in the program. Thus, in the program there is only one definition of the log function, the following: double log(double) {return 1.0;} .

Everything would be different if you extracted an object module containing log from the math library and directly linked it in your program. Since object modules are always included in the resulting program, while object modules in libraries are included only conditionally if they allow undefined characters.




Links from the standard:

The draft n3337 for C ++ 11 or n4296 for C ++ 14 (or n4618 for the latest revision) is explicit in Section 2.2 Translation Phases [lex.phases]:

§9. All references to external entities are permitted. Library components are linked to satisfy external references for objects not defined in the current translation . All such a translator displays an image in the program that contains the information necessary for execution in the runtime environment.

As shown in the code, only one translation unit is used, and log already defined in it, the definition from the library will not be used.

+2
Jan 16 '17 at 8:48
source share



All Articles