extern使っちゃダメな説

eye-catch C/C++
eye-catch

C++です。

タイトルの通り、回りくどいように聞こえる場合ははっきり言って差し上げましょう😇

グローバル変数使用したらダメ説です。

昔からPGerの間で定説となっている定番のディスりネタです。

よく言われるやっちゃいけないコーディングで、
「マジックナンバーダメ」
「定数ハードコーディングNG」
「ジャンプ命令使っちゃダメ」
「ヘッダファイルに処理実装して複数ファイルで流用」
などがありますが、これにグローバル変数使っちゃダメ説は含まれて説明されます。

今回作成中のプロジェクトでビルド時にエラーが発生しました。

デバッグビルドは成功するが、リリースビルドは失敗になる。

これは初めて経験しました🤔


externキーワードを使う

問題のエラーメッセージはこちら。

LNK2001エラー

これを見る限り、リンクの時に何か起きているように見えるのだが実際のところは構成をDebugにしてビルドをすると正常に通るという。

ちなみに上記のソースコードには案の定以下のようなコードになってました。

// includes.
#include "creditlogo_state.hpp"
#include <DxLib.h>
#include "openingdemo_state.hpp"
#include "src/domain/inputkey/c16key.hpp"
#include "src/domain/modules/factory/_clay/clays.hpp"
#include "src/domain/modules/factory/_clay/clay_diecast.hpp"
#include "src/domain/modules/factory/_clay/graphic_clay.hpp"
#include "src/domain/palette/formal/NES_default_color.hpp"


using namespace inputkey;

namespace modules {

    namespace phase {

        CreditLogoState::CreditLogoState() {
            using namespace factory;
            using namespace factory::interface__;
            abstract__::ClayDiecast* graph = new GraphicClay();
            IClays* gadget = graph->createDiv("assets/graphic_material/BG_tile/General/FLAT_NUMBER_PACK_30.png", 10, 10, 1, 8, 8);
            BG_.push_back(gadget);
            gadget = graph->createDiv("assets/graphic_material/BG_tile/General/FLAT_ALPHABETS_PACK_30.png", 32, 16, 2, 8, 8);
            BG_.push_back(gadget);
            palette::formal::NESPAL_0x15;
            circuit_.lounge = 0x01, circuit_.lap = 0x12, circuit_.counter = 0x08;
            delete graph;
        }

... (省略)
#ifndef ERIS_DOMAIN_PALETTE_FORMAL_NES_DEFAULT_COLOR_HPP_
#define ERIS_DOMAIN_PALETTE_FORMAL_NES_DEFAULT_COLOR_HPP_

namespace palette {

    namespace formal {

        extern const int NESPAL_0x00;
        extern const int NESPAL_0x15;

    }  // namespace formal

}  // namespace palette

#endif // !ERIS_DOMAIN_PALETTE_FORMAL_NES_DEFAULT_COLOR_HPP_
#ifndef ERIS_DOMAIN_PALETTE_FORMAL_NES_DEFAULT_COLOR_HPP_
#define ERIS_DOMAIN_PALETTE_FORMAL_NES_DEFAULT_COLOR_HPP_

// includes.
#include <DxLib.h>


namespace palette {

    namespace formal {

        const int NESPAL_0x00 = SetBackgroundColor(0x75, 0x75, 0x75);
        const int NESPAL_0x15 = SetBackgroundColor(0x00, 0x00, 0x00);

    }  // namespace formal

}  // namespace palette

#endif // !ERIS_DOMAIN_PALETTE_FORMAL_NES_DEFAULT_COLOR_HPP_

結論から言うと、今回問題視すべき箇所はプロジェクト・プロパティにありました。

それがこちら。

プロジェクトのプロパティぺージの構成プロパティ > 詳細 > プログラム全体の最適化

ちなみに構成Debugの設定は以下のようになっています。

私自身もなぜこのような設定になっているのか覚えておらず、初期値?かとも思いました。

プログラム全体の最適化とはそもそもなんでしょうか。

Microsoft Docに解説ぺージがあるようです。

/GL (プログラム全体の最適化)
詳細情報: /GL (プログラム全体の最適化)

そして私も一つ気になっていたのですが、なぜこの部分だけexternキーワードを使って、レガシーコードを書いてしまっているのか。

というかグローバル変数?

これは全体から参照するためにexternを使っているようにも見えますが、やはりクラスでラッピングしてしまったほうが良いでしょう…( ^ω^)

これはHACKコメント追記ですね🤗


2022年2月11日 20時30分 追記

上記のソースファイル、よく見ると NESPAL_0x00 … の実装を書いている部分、なぜかインクルードガードを張っており、なおかつヘッダファイルをIncludeしておりませんでした。

単純にそのミスに気づいておらずコンパイル結果からexternリンケージに問題があるものと勘違いしていたという誤爆案件でした😂

お詫びして訂正いたします。

(修正後ソースコード)

// includes.
#include "NES_default_color.hpp"
#include <DxLib.h>


namespace palette {

    namespace formal {

        const int NESPAL_0x00 = SetBackgroundColor(0x75, 0x75, 0x75);
        const int NESPAL_0x15 = SetBackgroundColor(0x00, 0x00, 0x00);

    }  // namespace formal

}  // namespace palette

コメント

タイトルとURLをコピーしました