Outils pour utilisateurs

Outils du site


lang:cpp:lieur

Mangling

Les méthodes définies dans un entête ont un attribut weak

Le corps d'une méthode template doit être identique quelque soit le fichier objet généré. Les méthodes template étant compilés dans chaque fichier objet (possibilité de nombreux doublons), le compilateur va leur donner l'attribut weak.

Si l'implémentation n'est toujours identique, le compilateur va en prendre une au hasard et la généraliser.

  • Exemple :
cpp/linker/weak/Entete.h
#pragma once
 
#include <iostream>
 
class Entete
{
 public:
  static void go()
  {
#ifdef HACK
    std::cout << "A" << std::endl;
#else
    std::cout << "B" << std::endl;
#endif
  }
};
cpp/linker/weak/ClasseA.h
#pragma once
 
class A
{
 public:
  static void go();
};
cpp/linker/weak/ClasseB.h
#pragma once
 
class B
{
 public:
  static void go();
};
cpp/linker/weak/ClasseA.cpp
#define HACK
 
#include "ClasseA.h"
#include "Entete.h"
 
void A::go() { Entete::go(); }
cpp/linker/weak/ClasseB.cpp
#undef HACK
 
#include "ClasseB.h"
#include "Entete.h"
 
void B::go() { Entete::go(); }
cpp/linker/weak/main.cpp
#include "ClasseA.h"
#include "ClasseB.h"
 
int main()
{
  A::go();
  B::go();
}
  • Symboles :
cpp/linker/weak/ClasseA.cpp.nm
                 U __cxa_atexit
                 U __dso_handle
                 U _GLOBAL_OFFSET_TABLE_
000000000000005d t _GLOBAL__sub_I__ZN1A2goEv
0000000000000010 t __static_initialization_and_destruction_0(int, int)
0000000000000000 T A::go()
0000000000000000 W Entete::go()
                 U std::ostream::operator<<(std::ostream& (*)(std::ostream&))
                 U std::ios_base::Init::Init()
                 U std::ios_base::Init::~Init()
                 U std::cout
                 U std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
0000000000000000 r std::piecewise_construct
0000000000000000 b std::__ioinit
                 U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
cpp/linker/weak/ClasseB.cpp.nm
                 U __cxa_atexit
                 U __dso_handle
                 U _GLOBAL_OFFSET_TABLE_
000000000000005d t _GLOBAL__sub_I__ZN1B2goEv
0000000000000010 t __static_initialization_and_destruction_0(int, int)
0000000000000000 T B::go()
0000000000000000 W Entete::go()
                 U std::ostream::operator<<(std::ostream& (*)(std::ostream&))
                 U std::ios_base::Init::Init()
                 U std::ios_base::Init::~Init()
                 U std::cout
                 U std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
0000000000000000 r std::piecewise_construct
0000000000000000 b std::__ioinit
                 U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)

On voit que le symbole Entete::go() est défini deux fois avec l'attribut weak. Mais le #define étant différent, les deux implémentations sont différentes.

lang/cpp/lieur.txt · Dernière modification : 2023/07/28 09:48 de root