【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
takahashi

【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#1

投稿記事 by takahashi » 3年前

ソースファイルを作らずにクラスの静的メンバ変数の実態を生成したいです。小さなものであればわざわざソースファイルは作りたくないという理由です。
次のようなdefクラスを作ってwindowサイズを静的メンバ変数として用意しました。

Def.h

コード:

#pragma once

class Def
{
public:
	static const int windowWidth;
	static const int windowHeight;
};

const int Def::windowWidth = 480;
const int Def::windowHeight = 360;
いろいろと調べたらこのファイルを2回以上インクルードしたら多重定義になってしまうらしくエラーが起きてしまうらしいのです。
ですが、現状普通に動作しています。
C++のバージョンの変化なのか、この書き方は普通に大丈夫なんなのかわかりません。

環境
OS : WIndows
コンパイラ:わからないのですがvisualstudio2019を使ってます。

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#2

投稿記事 by Meta3 » 3年前

#pragma once
が記述してあるから大丈夫ですよ。

コード:

#include <iostream>
#include "c1.hpp"
#include "c1.hpp"
using namespace std;

int main()
{
    cout << Def::windowWidth << endl;
}

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#3

投稿記事 by Meta3 » 3年前

visualstudio2019を使ってます。

コード:

c:\b>cpp

c:\b>cl /EHsc c1.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.26.28806 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.cpp
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:c1.exe
c1.obj

c:\b>c1.exe
480

c:\b>

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#4

投稿記事 by Meta3 » 3年前

>ソースファイルを作らずにクラスの静的メンバ変数の実態を生成したいです。小さなものであればわざわざソースファイルは作りたくないという理由です。


static(クラスの静的メンバ変数)は実態(実体 インスタンスのことね)を生成しなくても使えますよ。

でも さすがにソースファイルを作ら無ければ動かないですよ。

takahashi

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#5

投稿記事 by takahashi » 3年前

回答ありがとうございます!
progma onceがあるから多重定義にならないんですね!これがほしい回答でした。
質問の仕方が悪くて、意図が伝えられてませんでした。

さきほど用意したクラスのDef.hがあると思うのですが、普通ならDef.hとDef.cppに分けるのが一般的だと調べてたらでてきました。次の通りです。

Def.h

コード:

#pragma once

class Def
{
public:
	static const int windowWidth;
	static const int windowHeight;
};
Def.cpp

コード:

#include "Def.h"
const int Def::windowWidth = 480;
const int Def::windowHeight = 360;
このくらい小さかったらわざわざファイル分けたくないなーと思い一つにまとめたのが最初の質問の次のクラスです。

コード:

#pragma once

class Def
{
public:
	static const int windowWidth;
	static const int windowHeight;
};

const int Def::windowWidth = 480;
const int Def::windowHeight = 360;
このDef.hをmain.cppで呼び出して使おうとしてました。
しかし、質問でも言った通り次の箇所がヘッダーに書くと多重定義になってしまうと思ってたのですが普通に動作してたので不安になり質問しました。
const int Def::windowWidth = 480;
const int Def::windowHeight = 360;

ただ#pragma onceがあることでそれが防げるとわかったので解決しました。
ありがとうございます!

アバター
usao
記事: 1887
登録日時: 11年前

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#6

投稿記事 by usao » 3年前

> 多重定義になってしまう

という話は,インクルードガード(#pragma once)に関連する話ではなく,
「そのヘッダを A.cpp と B.cpp がincludeした場合に多重定義になる」という側の話であるように思うが.

試しに,そのクラスDef に static const メンバとして int ではない std::string 型とか適当な物を持たせて,
その実態を Def.h に定義した状態で,
Def.hを複数のcppからincludeしてみればわかる.

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#7

投稿記事 by Meta3 » 3年前

あ 失礼

Def.hーーーc1.hpp
main.cppーc1.hpp
として作りました

VisualStudio2019コマンドラインで実行ーーーcl /EHsc c1.cppーーー
c++はヘッダーは .hppを使うのが一般的

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#8

投稿記事 by Meta3 » 3年前

あ 失礼

Def.hーーーc1.hpp
main.cppーc1.hpp
として作りました

VisualStudio2019コマンドラインで実行ーーーcl /EHsc c1.cppーーー
c++はヘッダーは .hppを使うのが一般的

アバター
usao
記事: 1887
登録日時: 11年前

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#9

投稿記事 by usao » 3年前

static const int の場合にエラーにならないのは,それがガチの定数だからだと思う.
言わば特殊ケースであって,
「#pragma once とさえ書けば static なメンバの定義をヘッダファイルに書いて良い」という話ではない.

「さっきstringがどうの」と書いたが,もっと簡単に,constをハズしてみれば,エラーになることを確認できるハズ.


アバター
usao
記事: 1887
登録日時: 11年前

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#11

投稿記事 by usao » 3年前

> c++はヘッダーは .hppを使うのが一般的

・Boostとかだと ".hpp" が使われる
・Visual Studioでファイル新規追加する際の拡張子はC++でも".h"である.
・".hh" なんてのを使う文化もあるみたいだし.
・なんなら,STLは拡張子無いし.

「一般的」と言うほどの話とも思えないけど.

takahashi

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#12

投稿記事 by takahashi » 3年前

今までソースファイルがmain.cppの一つのみでプログラムを書いていたので動作していたんですね。
複数のソースファイル用意して、先ほどのクラスをincludeしたらエラーがでちゃんとでました。
やはりソースファイルとヘッダーファイルでわけるべきですね。
またヘッダーファイルというものが.h以外にもあるということが勉強になりました。
ありがとうございます。

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#13

投稿記事 by Meta3 » 3年前

c1.hpp

コード:

#pragma once

class Def
{
public:
	static const int windowWidth=480;
	static const int windowHeight=360;
};

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#14

投稿記事 by Meta3 » 3年前

c1.cpp

コード:

#include <iostream>
#include "c1.hpp"
#include "c1.hpp"
using namespace std;

extern int disp();

int main()
{
    cout << Def::windowWidth << endl;
    disp();
    return 0;
}

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#15

投稿記事 by Meta3 » 3年前

c2.cpp

コード:

#include <iostream>
#include "c1.hpp"

using namespace std;

int disp()
{
    cout << Def::windowHeight << endl;
    return 0;
}

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#16

投稿記事 by Meta3 » 3年前

エラーなんか出ないじゃないか
自作のヘッダーはcとかぶるときがあるから.hppにするといい VisualStudio2019使用

コード:

c:\b\p>cl /EHsc c1.cpp c2.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.26.28806 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.cpp
c2.cpp
コードを生成中...
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:c1.exe
c1.obj
c2.obj

c:\b\p>c1.exe
480
360

c:\b\p>
[code]c:\b\p>cl /EHsc c1.cpp c2.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.26.28806 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.cpp
c2.cpp
コードを生成中...
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:c1.exe
c1.obj
c2.obj

c:\b\p>c1.exe
480
360

c:\b\p>

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#17

投稿記事 by Meta3 » 3年前

C++ は C#のように開発責任者アンダース・ヘルスバーグ https://ja.wikipedia.org/wiki/%E3%82%A2 ... C%E3%82%B0 がいるわけではなく たくさんの処理系・実装がある
だから マイクロソフトのVisualStudio2019を使ってC17準拠での話 とか言わないと正確に言えない言語です
わたしはC#を先に使ったので分かりやすかった
C#の#はC++++の意味で(#は分解すると++++)C++はC#を追っかけている

C++を学ぶならC#を先に学ぶことをお勧めします

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#18

投稿記事 by Meta3 » 3年前

VisualStudio2019では
cl c1.c とすればC言語
cl /EHsc c1.cpp  とすればC++言語
としてビルドしてくれる 

ところが
cl /P c1.c  とするとC++言語
としてビルドしてくれる 
逆に
cl /C c1.cpp  とすればC言語
としてビルドしてくれる 
これは便利である 
C言語と「C++言語としてのC言語」が微妙にが違うからである

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#19

投稿記事 by Meta3 » 3年前

/P-----/TP
/C-----/TC
の間違い

VisualStudioではC++の開発が行えます。しかし、C++とC言語は微妙にちがいます。
たとえば、型変換や、intの省略などで違いが出てきます。C++はC言語よりも安全性と正確性を高めるための工夫がされています。

なのでC言語用に作られたプログラムをコンパイルしようとすると、その違いのせいでコンパイルエラーになることがしばしばあります。

では純粋なC言語としてコンパイルすることは出来ないのか?いえ、実は簡単に出来ます。
意外と知らない人がいるようなので
VisualStudio2019
cl ヘルプ
/Tc<source file> ファイルを .c としてコンパイルする
/Tp<source file> ファイルを .cpp としてコンパイルする
/TC すべてのファイルを .c としてコンパイルする
/TP すべてのファイルを .cpp としてコンパイルする

参照魚
記事: 109
登録日時: 6年前

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#20

投稿記事 by 参照魚 » 3年前

static inline と宣言すればいけると思います。

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#21

投稿記事 by Meta3 » 3年前

最初にみたときこんな冗談のようなソースで動かないだろうと思ったが動くのことでヘッダーを忠実に最初のものにしてビルドしてアセンブリーにおとしてみました
c1.hpp

コード:

#pragma once

class Def
{
public:
	static const int windowWidth;
	static const int windowHeight;
};

const int Def::windowWidth = 480;
const int Def::windowHeight = 360;
c1.hpp

コード:

#include <iostream>
#include "c1.hpp"
#include "c1.hpp"
using namespace std;

extern int disp();

int main()
{
    return 0;
}

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#22

投稿記事 by Meta3 » 3年前

コード:

c:\b\p>cpp

c:\b\p>del c1.exe

c:\b\p>cl /EHsc c1.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.26.28806 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.cpp
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:c1.exe
c1.obj

c:\b\p>c1.exe

c:\b\p>cl /Fa c1.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.26.28806 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.cpp
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:c1.exe
c1.obj

c:\b\p>

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#23

投稿記事 by Meta3 » 3年前

コード:

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.26.28806.0 

	TITLE	c:\b\p\c1.cpp
	.686P
	.XMM
	include listing.inc
	.model	flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC	?windowWidth@Def@@2HB				; Def::windowWidth
PUBLIC	?windowHeight@Def@@2HB				; Def::windowHeight
CONST	SEGMENT
?windowWidth@Def@@2HB DD 01e0H				; Def::windowWidth
?windowHeight@Def@@2HB DD 0168H				; Def::windowHeight
CONST	ENDS
PUBLIC	_main
; Function compile flags: /Odtp
_TEXT	SEGMENT
_main	PROC
; File c:\b\p\c1.cpp
; Line 9
	push	ebp
	mov	ebp, esp
; Line 10
	xor	eax, eax
; Line 11
	pop	ebp
	ret	0
_main	ENDP
_TEXT	ENDS
END



Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#26

投稿記事 by Meta3 » 3年前

>static inline と宣言すればいけると思います。

そうですね。
https://cpprefjp.github.io/lang/cpp17/i ... ables.html

[外部リンケージを持つ変数に対しインラインinlineを指定することで、複数の翻訳単位で同じ変数を宣言できるようになり、変数の実体はただ一つとすることができる。

C++14までは関数のみインライン指定ができたが、C++17では関数、変数ともにインライン指定が可能になった。

これによりヘッダのみで変数の定義を行うことができるようになり、従来のようにヘッダで変数を宣言しソースで変数の実体を定義する必要がなくなった。]

参照魚
記事: 109
登録日時: 6年前

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#27

投稿記事 by 参照魚 » 3年前

実行中に値が変更されないのであれば、constexprで宣言する方があっているかと思います。

static constexpr int windowWidth = 480;
static constexpr int windowHeight = 360;

Meta3

Re: 【C++】ソースファイルを作らずに静的メンバ変数の実態の生成

#28

投稿記事 by Meta3 » 3年前

「なるほど ROM に置ける値か」

これまでconst修飾してきたものには2種類あった、ひとつはROM化可能な値、もうひとつは実行時にしか決まらないがいったん初期化したあとは二度と変更されない値である。C++11以降、前者はconstexprが受け持ち、後者はconstが受け持つことになった。
constexpr指定子は、constexprの制約を満たした変数の定義、関数と関数テンプレートの宣言、staticデータメンバーの宣言に対して使用できる。
2つの区別
constは型修飾子である。const intはint型であるが、初期化したあとは二度と変更されない変数である。C++11以降、constexprが導入されたあとは、constはRAMにしか配置できない変数に対して使う修飾子となった。
constexprは型修飾子ではなく、型指定子である。型を修飾するものでなく、ROM化できる、または、ROM化できる可能性がある、という意味を持つ指定子である。
https://qiita.com/saltheads/items/dd65935878a0901fe9e7

返信

“C言語何でも質問掲示板” へ戻る