web-dev-qa-db-ja.com

名前マングリングとは何ですか、そしてそれはどのように機能しますか?

名前マングリングとは何か、それがどのように機能するか、どのような問題を解決するか、そしてどのコンテキストと言語が使用されているかを説明してください。名前マングリング戦略(たとえば、コンパイラーが選択する名前とその理由)はプラスです。

45
Stefano Borini

選択したプログラミング言語では、識別子が個別にコンパイルされたユニットからエクスポートされる場合、リンク時に認識される名前が必要です。名前マングリングオーバーロードされた識別子の問題を解決しますプログラミング言語で。 (同じ名前が複数のコンテキストで使用されている場合、または複数の意味で使用されている場合、識別子は「オーバーロード」されます。)

いくつかの例:

  • C++では、関数またはメソッドgetが複数のタイプでオーバーロードされる場合があります。

  • AdaまたはModula-3では、関数getが複数のモジュールに表示される場合があります。

複数のタイプと複数のモジュールが通常のコンテキストをカバーします。

典型的な戦略:

  • 各タイプを文字列にマップし、結合された高レベルの識別子と「タイプ文字列」をリンク時の名前として使用します。 C++(オーバーロードは関数/メソッドと引数タイプでのみ許可されるため特に簡単)とAda(結果タイプもオーバーロードできる)で一般的です。

  • 識別子が複数のモジュールまたは名前空間で使用されている場合は、モジュールの名前を識別子の名前と結合します(例:List_get の代わりに List.get

リンク時の名前で有効な文字によっては、追加のマングリングが必要になる場合があります。たとえば、区別できるように、アンダースコアを「エスケープ」文字として使用する必要がある場合があります。

  • List_my.get-> List__my_get

から

  • List.my_get-> List_my__get

(確かにこの例は到達していますが、コンパイラの作成者として、ソースコード内の個別の識別子が個別のリンク時名にマップされるであることを保証する必要があります。これが名前マングリングの理由と目的です。)

38
Norman Ramsey

簡単に言えば、名前マングリングは、コンパイラがソースコード内の識別子の名前を変更して、それらの識別子間の曖昧さを解消するのに役立つ linker を支援するプロセスです。

ウィキペディアにはこのテーマに関するすばらしい記事があります いくつかのすばらしい例があります。

25
Andrew Hare

名前マングリング は、コンパイラがオブジェクトの「コンパイルされた」名前を変更して、一貫した方法で指定したものとは異なるものにする手段です。

これにより、プログラミング言語は、コンパイルされた複数のオブジェクトに同じ名前を柔軟に提供でき、適切なオブジェクトを一貫して検索できます。たとえば、これにより、同じ名前の複数のクラスが異なる名前空間に存在できるようになります(多くの場合、クラス名の前に名前空間を追加するなど)。

多くの言語での演算子とメソッドのオーバーロードは、これをさらに一歩進めます。1つのタイプに複数のメソッドが同じ名前で存在できるようにするために、各メソッドはコンパイル済みライブラリに「マングル」名で終わります。

5
Reed Copsey

出典: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

名前マングリングは、C++コンパイラが使用するプロセスであり、プログラム内の各関数に一意の名前を付けます。 C++では、通常、プログラムには少なくとも同じ名前の関数がいくつかあります。したがって、名前マングリングはC++の重要な側面と見なすことができます。

例:通常、メンバー名は、メンバーの名前をクラスの名前と連結することによって一意に生成されます。宣言が与えられた:

class Class1
 {
        public:
            int val;
            ...
  };

valは次のようになります。

  // a possible member name mangling
     val__11Class1
2
Santosh

Pythonでは、名前マングリングは、クラス変数がクラスの内部と外部で異なる名前を持つシステムです。プログラマーは、変数名の先頭に2つのアンダースコアを付けることにより、それを「アクティブ化」します。

たとえば、いくつかのメンバーで単純なクラスを定義できます。

>>> class Foo(object):
...  def __init__(self):
...   self.x = 3
...   self._y = 4
...   self.__z = 5
... 

pythonプラクティスでは、アンダースコアで始まる変数名は「内部」であり、クラスインターフェイスの一部ではないため、プログラマーはこれに依存しないでください。ただし、引き続き表示されます。

>>> f = Foo()
>>> f.x
3
>>> f._y
4

2つのアンダースコアで始まる変数名はまだ公開されていますが、名前が壊れているため、アクセスが困難です。

>>> f.__z  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__z'

ただし、名前マングリングがどのように機能するかを知っていれば、次のことがわかります。

>>> f._Foo__z
5

つまり、クラス名の前に変数名の前にアンダースコアが追加されます。

Pythonには、「プライベート」メンバーと「パブリック」メンバーの概念はありません。すべてが公開されています。名前マングリングは、クラスの外部から変数にアクセスしてはならないというプログラマーが送信できる最も強力なシグナルです。

2
John Fouhy

リンクエディタが設計された時点では、C、FORTAN、COBOLなどの言語には、名前空間、クラス、クラスのメンバーなどがありませんでした。名前マングリングは、それらをサポートしないリンクエディタを備えた機能などのオブジェクト指向機能をサポートするために必要です。リンクエディタが追加機能をサポートしていないという事実は、見過ごされがちです。人々は、リンクエディタのために名前マングリングが必要であると言うことによってそれを暗示します。

名前マングリングが行うことをサポートするための言語要件には非常に多くのバリエーションがあるため、リンクエディタでそれをサポートする方法の問題に対する簡単な解決策はありません。リンクエディタは、さまざまなコンパイラからの出力(オブジェクトモジュール)で動作するように設計されているため、名前をサポートするための普遍的な方法が必要です。

0
user34660

Fortranでは、言語で大文字と小文字が区別されないため、名前のマングリングが必要です。つまり、Foo、FOO、fOo、fooなどはすべて同じシンボルに解決され、その名前は何らかの方法で正規化する必要があります。コンパイラが異なれば、マングリングの実装も異なります。これは、異なるコンパイラでコンパイルされたCまたはバイナリオブジェクトとインターフェイスするときに大きな問題の原因になります。 GNU g77/g95など、名前にすでに1つ以上のアンダースコアが含まれている場合を除き、小文字の名前には常に末尾のアンダースコアが追加されます。この場合、2つのアンダースコアが追加されます。

たとえば、次のルーチン

    program test
    end program 

    subroutine foo()
    end subroutine

    subroutine b_ar()
    end subroutine
    subroutine b_a_r()
    end subroutine

次のマングルシンボルを生成します。

0000000000400806 g     F .text  0000000000000006              b_ar__
0000000000400800 g     F .text  0000000000000006              foo_
000000000040080c g     F .text  0000000000000006              b_a_r__

CからFortranコードを呼び出すには、適切にマングルされたルーチン名を呼び出す必要があります(明らかに、コンパイラーに依存しない可能性のあるさまざまなマングリング戦略を考慮に入れてください)。 fortranからCコードを呼び出すには、Cで記述されたインターフェースが適切にマングルされた名前をエクスポートし、その呼び出しをCルーチンに転送する必要があります。このインターフェースは、Fortranから呼び出すことができます。

0
Stefano Borini

ここでの答えは素晴らしいので、これは私の小さな経験からの単なる追加です:私は名前マングリングを使用して、どのツール(gcc/vs/...)、どのようにパラメーターがスタックに渡されるか、そして私がどの呼び出し規約であるかを知るために使用しますを扱っており、名前に基づいているので、たとえば_mainを参照すると、他の人もCdecl同じであることがわかります。

0
zerocool

これまでの答えはすべて正しいですが、ここにPythonパースペクティブ/例を挙げた理由があります。

定義

クラス内の変数の接頭辞が__(つまり、2つのアンダースコア)で、接尾辞が__(つまり、2つのアンダースコア以上)でない場合、その変数はプライベート識別子と見なされます。 Pythonインタープリターは任意のプライベート識別子を変換し、名前を_class__identfierにマングルします

Example:
MyClassName --> _myClassName
__variable --> __variable

なぜ

これが必要なのは、属性のオーバーライドによって引き起こされる可能性のある問題を回避するためです。言い換えると、オーバーライドするには、Pythonインタープリターは、子メソッドと親メソッドの個別のIDを作成し、__(二重アンダースコア)enable pythonこれを行うには。以下の例では、__ helpがないとこのコードは機能しません。

class Parent:
    def __init__(self):
       self.__help("will take child to school")
    def help(self, activities):
        print("parent",activities)

    __help = help   # private copy of original help() method

class Child(Parent):
    def help(self, activities, days):   # notice this has 3 arguments and overrides the Parent.help()
        self.activities = activities
        self.days = days
        print ("child will do",self.activities, self.days)


# the goal was to extend and override the Parent class to list the child activities too
print ("list parent & child responsibilities")
c = Child()
c.help("laundry","Saturdays")
0
grepit

オブジェクト指向言語のほとんどは、関数のオーバーロード機能を提供します。 関数のオーバーロードクラスに同じ名前でパラメーターのタイプと番号が異なる複数の関数がある場合、それらはオーバーロードされていると言われます。関数のオーバーロードにより、異なる関数に同じ名前を使用できます。

関数をオーバーロードする方法

  1. 引数の数を変更する。
  2. リストアイテムさまざまなタイプの引数を持つことによって。

名前マングリングで関数のオーバーロードはどのように達成されますか?
C++コンパイラは、オブジェクトコードを生成するときにさまざまな関数を区別します。引数の種類と数に基づいて引数に関する情報を追加することにより、名前を変更します。関数名を形成するために追加情報を追加するこの手法は、名前マングリングと呼ばれます。 C++標準では、名前マングリングの特定の手法が指定されていないため、コンパイラが異なれば、関数名に異なる情報が追加される可能性があります。 gcc4.8.4でサンプルプログラムを実行しました。

class ABC
{       
 public:
  void fun(long a, long b) {}
  void fun(float a, float b) {} 
  void fun(int a, float b) {}   
};
int main()
{
 ABC obj;
 obj.fun(1l,2l);
 obj.fun(1,2.3f);
 obj.fun(3.2f,4.2f);
 return 0;
}

このプログラムには、引数の数とそのタイプに基づいて異なるfunという名前の3つの関数があります。これらの関数名は次のようにマングルされています。

ayadav@gateway1:~$ nm ./a.out |grep fun
000000000040058c W _ZN3ABC3funEff
00000000004005a0 W _ZN3ABC3funEif
000000000040057a W _ZN3ABC3funEll
  • ABCはクラス名のコマンド文字列です
  • funは関数名の一般的な文字列です
  • ff2つのfloat-> fタイプの引数
  • ll2つのlong-> lタイプの引数
  • 最初の整数引数-> iと1つのfloat-> f引数の場合
0
Ajay yadav