Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 15034] ファイルの概要

このコミットは、Go言語のツールチェインの一部であるcmd/5l(ARMアーキテクチャ向けのリンカ)における、C言語の構造体Adr内の共用体(union)フィールドの命名規則を統一するための変更です。具体的には、共用体内の匿名構造体u0offのメンバーであるoffsetoffset2を、u0offsetu0offset2にリネームし、それに伴い関連する#defineマクロも更新しています。

コミット

commit e6861d8c34002b7f1b8a12b03672fda02f02d7ed
Author: Russ Cox <rsc@golang.org>
Date:   Wed Jan 30 09:10:06 2013 -0800

    cmd/5l: reestablish uniform union field naming
    
    R=golang-dev, minux.ma
    CC=golang-dev
    https://golang.org/cl/7226063

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/e6861d8c34002b7f1b8a12b03672fda02f02d7ed

元コミット内容

cmd/5l: reestablish uniform union field naming

変更の背景

この変更の背景には、Go言語のツールチェイン、特にリンカ部分のC言語で書かれたコードベースにおける、共用体(union)のフィールド命名の一貫性を確立するという目的があります。

Go言語の初期のツールチェインはC言語で実装されており、その中でリンカ(cmd/5lなど)もC言語で書かれていました。C言語の共用体は、異なる型のデータを同じメモリ領域に格納するための機能であり、しばしば構造体と組み合わせて使用されます。特に、匿名共用体や匿名構造体を使用する場合、フィールド名が重複したり、どの共用体や構造体に属するのかが不明瞭になったりする可能性があります。

このコミットメッセージにある「reestablish uniform union field naming」(共用体フィールドの統一的な命名を再確立する)という表現は、以前のコードベースで共用体内のフィールド命名に一貫性がなかったか、あるいは何らかの理由でその一貫性が失われたため、それを修正し、より明確で保守しやすいコードにする意図があったことを示唆しています。

具体的には、Adr構造体内の匿名共用体u0の内部にある匿名構造体u0offのメンバーであるoffsetoffset2が、共用体u0のメンバーであることを明示するためにu0offsetu0offset2にリネームされました。これにより、コードを読む際に、これらのフィールドがu0共用体の一部であることが一目でわかるようになり、名前の衝突を避け、コードの可読性と保守性を向上させることが期待されます。

前提知識の解説

Go Toolchainとcmd/5l

Go言語は、そのコンパイラ、リンカ、アセンブラなどのツールチェイン自体がGo言語で書かれていることで知られていますが、初期のバージョンではC言語で書かれた部分も多く存在しました。cmd/5lは、Go言語のツールチェインの一部であり、具体的にはARMアーキテクチャ(GOARCH=arm)向けのリンカを担当していました。リンカは、コンパイラによって生成されたオブジェクトファイル(機械語コード)を結合し、実行可能なバイナリファイルを生成する役割を担います。

C言語の構造体(Struct)と共用体(Union)

  • 構造体(Struct): 異なる型のデータをまとめて一つの論理的な単位として扱うためのデータ構造です。構造体の各メンバーは、それぞれ異なるメモリ領域を占有します。
    struct Point {
        int x;
        int y;
    };
    
  • 共用体(Union): 異なる型のデータを同じメモリ領域に格納するためのデータ構造です。共用体のメンバーはメモリを共有するため、一度に一つのメンバーの値しか保持できません。共用体のサイズは、その中で最も大きいメンバーのサイズによって決まります。
    union Data {
        int i;
        float f;
        char s[20];
    };
    
  • 匿名共用体(Anonymous Union): C11標準で導入された機能で、共用体の名前を省略して定義できます。匿名共用体のメンバーは、共用体を含む構造体のメンバーであるかのように直接アクセスできます。
    struct Adr {
        // ...
        union { // 匿名共用体
            struct {
                int offset;
                int offset2;
            } u0off;
            char* u0sval;
            // ...
        }; // 共用体名がない
        // ...
    };
    // アクセス例: adr.u0off.offset (匿名共用体なので adr.offset とはできない)
    
    ただし、このコミットのコードでは、共用体自体にはu0という名前が付けられています。
    struct Adr {
        // ...
        union
        {
            struct {
                int offset;
                int offset2; // argsize
            } u0off;
            char* u0sval;
            Ieee u0ieee;
            // ...
        } u0; // 共用体名が 'u0'
        // ...
    };
    // アクセス例: adr.u0.u0off.offset
    
    この場合、u0は共用体の名前であり、その中のu0offは匿名構造体ではありません。u0offu0共用体内の構造体メンバーです。

#defineプリプロセッサディレクティブ

C言語のプリプロセッサディレクティブである#defineは、マクロを定義するために使用されます。これにより、コード内の特定の文字列を別の文字列に置換することができます。これは、定数を定義したり、複雑な式を簡略化したり、あるいは今回のケースのように、構造体や共用体の深い階層にあるメンバーへのアクセスを短縮するためのエイリアスを作成したりするのに使われます。

#define offset u0.u0off.offset

この定義により、コード中でoffsetと書くと、プリプロセッサによってu0.u0off.offsetに置換されます。

命名規則の重要性

大規模なソフトウェアプロジェクトにおいて、一貫性のある命名規則は極めて重要です。

  • 可読性: コードが読みやすくなり、他の開発者がコードの意図を素早く理解できるようになります。
  • 保守性: 命名規則が守られていると、バグの特定や機能追加が容易になります。
  • 衝突の回避: 異なるスコープで同じ名前が使われることによる名前の衝突(name collision)を防ぎます。
  • 検索性: 特定の機能やデータに関連するコードを検索しやすくなります。

今回の変更は、共用体内のフィールドに共用体名(u0)をプレフィックスとして付与することで、そのフィールドがどの共用体に属するのかを明確にし、命名の一貫性を高めることを目的としています。

技術的詳細

このコミットは、src/cmd/5l/l.hファイル内のAdr構造体の定義と、それに関連する#defineマクロを変更しています。

変更の核心は、Adr構造体内の共用体u0の内部にある匿名構造体u0offのメンバーであるoffsetoffset2の命名変更です。

変更前:

struct Adr
{
    union
    {
        struct {
            int32   offset;
            int32   offset2; // argsize
        } u0off;
        char*   u0sval;
        Ieee    u0ieee;
        // ...
    } u0;
    // ...
};

#define offset  u0.u0off.offset
#define offset2 u0.u0off.offset2

変更後:

struct Adr
{
    union
    {
        struct {
            int32   u0offset;  // 変更点
            int32   u0offset2; // argsize // 変更点
        } u0off;
        char*   u0sval;
        Ieee    u0ieee;
        // ...
    } u0;
    // ...
};

#define offset  u0.u0off.u0offset  // 変更点
#define offset2 u0.u0off.u0offset2 // 変更点

この変更により、u0off構造体内のフィールド名がu0共用体のメンバーであることを明示するu0プレフィックスを持つようになりました。これは、コードの可読性を向上させ、将来的な名前の衝突を防ぐための一般的な命名規則の適用です。

また、これらのフィールドにアクセスするための#defineマクロも、新しいフィールド名に合わせて更新されています。これにより、既存のコードベースでoffsetoffset2というマクロを使用している箇所は、自動的に新しいフィールド名に解決されるため、マクロを使用している側のコードを変更する必要がなくなります。これは、大規模なコードベースでリファクタリングを行う際の一般的な手法であり、影響範囲を最小限に抑えつつ、内部的な構造を改善することができます。

この変更は、Go言語のリンカがC言語で書かれていた時代のコード品質と保守性を向上させるための、細かながらも重要な改善点と言えます。

コアとなるコードの変更箇所

diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index abfd7e12ab..0a04559e9a 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -69,8 +69,8 @@ struct Adr
  	union
  	{
  		struct {
- 		int32	offset;
- 		int32	offset2; // argsize
+ 		int32	u0offset;
+ 		int32	u0offset2; // argsize
  		} u0off;
  		char*	u0sval;
  		Ieee	u0ieee;
@@ -84,8 +84,8 @@ struct Adr
  	char	class;
  };
  
-#define	offset	u0.u0off.offset
-#define	offset2	u0.u0off.offset2
+#define	offset	u0.u0off.u0offset
+#define	offset2	u0.u0off.u0offset2
  #define	sval	u0.u0sval
  #define	scon	sval
  #define	ieee	u0.u0ieee

コアとなるコードの解説

上記のdiffは、src/cmd/5l/l.hファイルに対する変更を示しています。

  1. struct Adr内の共用体フィールド名の変更:

    • - int32 offset; から + int32 u0offset;
    • - int32 offset2; // argsize から + int32 u0offset2; // argsize この変更は、Adr構造体内のu0という名前の共用体の中に定義されている匿名構造体u0offのメンバーであるoffsetoffset2の名前を、それぞれu0offsetu0offset2に変更しています。この命名規則の変更は、これらのフィールドがu0共用体の一部であることを明示し、コードの可読性と一貫性を向上させることを目的としています。// argsizeというコメントは、offset2が引数のサイズを表すために使われることを示しています。
  2. #defineマクロの更新:

    • - #define offset u0.u0off.offset から + #define offset u0.u0off.u0offset
    • - #define offset2 u0.u0off.offset2 から + #define offset2 u0.u0off.u0offset2 これらの変更は、以前のoffsetoffset2というマクロ定義を、新しいフィールド名u0offsetu0offset2に合わせて更新しています。これにより、コードベースの他の場所でこれらのマクロを使用している場合でも、変更されたフィールド名に透過的にアクセスできるようになります。これは、APIの互換性を保ちつつ、内部実装をリファクタリングする一般的な手法です。

全体として、このコミットは、Go言語のリンカのC言語コードベースにおける内部的な命名規則を改善し、コードの明確性と保守性を高めるためのクリーンアップ作業の一環です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (Go Toolchainに関する情報): https://go.dev/doc/
  • C言語の構造体と共用体に関する一般的な情報源 (例: C言語のチュートリアルやリファレンス)
  • C言語のプリプロセッサに関する一般的な情報源 (例: C言語のチュートリアルやリファレンス)
  • Go言語の初期のツールチェインがC言語で書かれていたことに関する歴史的背景 (Go言語の歴史に関する記事やドキュメント)
  • Go言語のリンカに関する情報 (Go言語のコンパイラ/リンカの内部構造に関する技術記事や論文)