名前マングリングとは何か、それがどのように機能するか、それがどのような問題を解決するか、そしてどのコンテキストと言語が使用されているかを説明してください。名前マングリング戦略(たとえば、コンパイラーが選択する名前とその理由)はプラスです。
10 に答える
選択したプログラミング言語では、識別子が個別にコンパイルされたユニットからエクスポートされる場合、リンク時に認識される名前が必要です。名前マングリングは、プログラミング言語でのオーバーロードされた識別子の問題を解決します。(同じ名前が複数のコンテキストで使用されている場合、または複数の意味で使用されている場合、識別子は「オーバーロード」されます。)
いくつかの例:
C ++では、関数またはメソッド
get
が複数のタイプでオーバーロードされる場合があります。AdaまたはModula-3では、機能
get
が複数のモジュールに表示される場合があります。
複数のタイプと複数のモジュールが通常のコンテキストをカバーします。
典型的な戦略:
各タイプを文字列にマップし、リンク時の名前として高レベルの識別子と「タイプ文字列」を組み合わせて使用します。C ++(オーバーロードは関数/メソッドと引数タイプでのみ許可されるため特に簡単)とAda(結果タイプもオーバーロードできる)で一般的です。
識別子が複数のモジュールまたは名前空間で使用されている場合は、モジュールの名前を識別子の名前と結合します。たとえば、の
List_get
代わりにList.get
。
リンク時の名前で有効な文字によっては、追加のマングリングが必要になる場合があります。たとえば、アンダースコアを「エスケープ」文字として使用する必要がある場合があります。これにより、区別できるようになります。
List_my.get
->List__my_get
から
List.my_get
->List_my__get
(確かにこの例は到達していますが、コンパイラーの作成者として、ソースコード内の個別の識別子が個別のリンク時名にマップされることを保証する必要があります。これが名前マングリングの理由と目的です。)
簡単に言うと、名前マングリングは、リンカーがそれらの識別子を明確にするのを支援するために、コンパイラがソースコード内の識別子の名前を変更するプロセスです。
ウィキペディアには、このテーマに関するすばらしい記事がいくつかあり、いくつかのすばらしい例があります。
名前マングリングは、コンパイラーがオブジェクトの「コンパイルされた」名前を変更して、一貫した方法で指定したものとは異なるものにするための手段です。
これにより、プログラミング言語は、コンパイルされた複数のオブジェクトに同じ名前を柔軟に提供でき、適切なオブジェクトを一貫して検索できます。たとえば、これにより、同じ名前の複数のクラスが異なる名前空間に存在できるようになります(多くの場合、クラス名の前に名前空間を追加するなど)。
多くの言語での演算子とメソッドのオーバーロードは、これをさらに一歩進めます。1つのタイプに複数のメソッドが同じ名前で存在できるようにするために、各メソッドはコンパイル済みライブラリに「マングル」名で終わります。
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には、「プライベート」メンバーと「パブリック」メンバーの概念はありません。すべてが公開されています。名前マングリングは、クラスの外部から変数にアクセスしてはならないというプログラマーが送信できる最も強力なシグナルです。
出典: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
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から呼び出すことができます。
オブジェクト指向言語のほとんどは、関数のオーバーロード機能を提供します。 関数のオーバーロード クラスに同じ名前でパラメータのタイプと番号が異なる複数の関数がある場合、それらはオーバーロードされていると言われます。関数のオーバーロードにより、異なる関数に同じ名前を使用できます。
関数をオーバーロードする方法
- 引数の数を変更する。
- リストアイテムさまざまなタイプの引数を持つことによって。
名前マングリングで関数のオーバーロードはどのように達成されますか?
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引数の場合
リンクエディタが設計された時点では、C、FORTAN、COBOLなどの言語には、名前空間、クラス、クラスのメンバーなどがありませんでした。名前マングリングは、それらをサポートしないリンクエディタを備えた機能などのオブジェクト指向機能をサポートするために必要です。リンクエディタが追加機能をサポートしていないという事実は、見過ごされがちです。人々は、リンクエディタのために名前マングリングが必要であると言うことによってそれを暗示します。
名前マングリングが行うことをサポートするための言語要件には非常に多くのバリエーションがあるため、リンクエディタでそれをサポートする方法の問題に対する簡単な解決策はありません。リンクエディタは、さまざまなコンパイラからの出力(オブジェクトモジュール)で動作するように設計されているため、名前をサポートするための普遍的な方法が必要です。
これまでの答えはすべて正しいですが、ここにPythonの視点/例を挙げた理由があります。
意味
クラス内の変数のプレフィックスが__(つまり、2つのアンダースコア)で、サフィックスが__(つまり、2つのアンダースコア以上)でない場合、それはプライベートIDと見なされます。Pythonインタープリターは任意のプライベート識別子を変換し、名前を_class__identfierにマングルします
Example:
MyClassName --> _myClassName
__variable --> __variable
なぜ
これが必要なのは、属性のオーバーライドによって引き起こされる可能性のある問題を回避するためです。つまり、オーバーライドするには、Pythonインタープリターが子メソッドと親メソッドの個別のIDを作成できる必要があり、__(二重アンダースコア)を使用して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")
ここでの答えは素晴らしいので、これは私の小さな経験からの単なる追加です:私は名前マングリングを使用して、どのツール(gcc / vs / ...)とパラメーターがスタックに渡されるか、そして私がどの呼び出し規約であるかを知るために使用します扱っている、そしてそれは名前に基づいているので、例えば _main
私が見るならそれCdecl
は他の人にとっても同じだと知っている