g++ signature/symbol : no difference between static and non-static member function?

StackOverflow https://stackoverflow.com/questions/23296381

  •  09-07-2023
  •  | 
  •  

Question

Two libs that defines the same class A, in different ways (this is legacy-crap-code)

Prototypes for A:

in lib A:

#include <string>

struct A
{
     static void func( const std::string& value);
};

in lib B:

#include <string>

struct A
{
   void func( const std::string& value);
};

main.cpp uses A:s header from lib A (component A)

#include "liba.h"

int main()
{
    A::func( "some stuff");
    return 0;
}

main is linked with both lib A and lib B.

If lib B is "linked before" lib A (in the link-directive) we get a core, hence, lib B:s definition is picket.

This is not the behavior I expected. I thought that there would be some difference between the symbols, so the loader/runtime linker could pick the right symbol. That is, the hidden this-pointer for non-static member functions is somehow included in the symbol.

Is this really conformant behavior?

Same behavior on both:

g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)

RHEL devtool with g++ 4.8.1

Était-ce utile?

La solution

It is not possible to overload a non-static member function with a static one or viceversa. From the standard:

ISO 14882:2003 C++ Standard 13.1/2 – Overloadable declarations

Certain function declarations cannot be overloaded:

  • Function declarations that differ only in the return type cannot be overloaded.
  • Member function declarations with the same name and the same parameter types cannot be overloaded if any of them is a static member function declaration (9.4).

More details and references might be found in question 5365714.

So you have two definitions of the same class A in the same program, which should be identical, and they are not. To signal an error when there are inconsistent definitions in separate translation units is not mandatory for the linker. The result is implementation defined The program is ill-formed (updated as per @jonathan's comment). In an illustrating example from Stroustrup in the C++ faq it is described as undefined behavior.

In the case of GCC, as you said, the definition used depends on the order of the libraries in the link command (assuming lib A and lib B are compiled on itself, and then linked with the main program). The linker uses the first definition found in the libraries passed from left to right. A discussion on the link order options for GCC is in 409470.

Autres conseils

You cannot overload functions in C++ based on the return type, so I would guess that you cannot do it on basis of static/v-non-static member functions.

You will need to fix one of the header files -- preferably by not declaring the same type twice.

To illustrate look at this;

struct A {
    int X(int b);
};
int A::X(int b)
{
    return b+8;
}

$ g++ x.cc -c
$ nm x.o
0000000000000000 T _ZN1A1XEi

and compare it to this....

struct A {
    static int X(int b);
};
int A::X(int b)
{
    return b+8;
}

$ g++ x.cc -c
$ nm x.o
0000000000000000 T _ZN1A1XEi

And observe two things;

  1. Nowhere when I declared the actual implementation of A::X did I specify that it was a static member function -- the compiler didn't care, but took what ever information from the definition of struct.
  2. The name mangling of the symbol, whether static or not is the same _ZN1A1XEi which encodes the name of the class the name of the method and the type of the arguments.

So in conclusion, using incorrect headers against compiled code would lead to undefined behavior....

Since a class cannot have both a static member function and non-static member function with the same name, there's no need to include that information in the mangled name.

You will need to solve this problem by including namespaces for your classes, renaming them, or being careful not to use the libraries together.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top