質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

9194閲覧

文字列定数について(#defineかconstexprか)

torimingo

総合スコア122

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/08/28 12:58

文字列の定数を定義する方法について悩んでいます。
以下のコードの方法1と方法2では、どちらがよいのでしょうか?
それとももっと良い定義の方法があるのでしょうか?
ご教授頂けたら幸いです。

// 方法1 #define STR "abc" // 方法2 namespace constant { constexpr char str[] = "abc"; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

用途やコーディング規約次第で一概に何がいいとは決まらないと思います。

CのソースコードとC++のソースコードを併用するようなプロジェクトの場合は両方で使えるようにするには方法1にするしかありません。
C++のだけのプロジェクトだったら方法2で統一でもいいと思います。namespaceが使えて便利ですし。
方法1と方法2を併用する方法もあります。

あとdefineだと文字列リテラルを結合できたりします。これは方法2ではできないです。

C

1// 方法1 2#define STR1 "abc" 3#define STR2 "def"

C++

1// 方法2 2namespace constant 3{ 4 constexpr char str[] = STR1 "-" STR2; // "abc-def" 5}

投稿2019/08/28 13:18

nomuken

総合スコア1627

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/08/28 14:33

ご回答をありがとうございました。 どちらか一方でなければいけないというわけではないのですね。 勉強になりました。
guest

0

C++ はプリプロセッサの利用をなるべく少なくする方向に進歩しています。 C++17 ではインライン変数を使うという選択肢もあります。

プログラムの内容を理解せず字句を置き換えるだけのマクロはそれを利用したい場面も有るものの有害なことが多いとも考えられており、特にマクロの性質が必要であるような場面を除いては、つまりどちらでもよい場面ではマクロを使わない選択をするのが現代的なスタイルと言えるとは思います。

が、そうは言ってもマクロの性質が必要な場面もまだあるのも確かなので、結局のところはきちんと用途を見極めましょうという無難な結論になっちゃいますね。

投稿2019/08/28 14:45

SaitoAtsushi

総合スコア5461

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/08/28 21:43

ご回答ありがとうございます。 インライン変数をすこし調べてみたのですが、Cのinline指定とはまた違うんですかね・・・。 Cのinlineは、変数に付与すると最適化が行われないという感じのものだったと思うのですが・・・。 最適化が行われないということは、実行時間がわずかに増えたりするのかな?と考えてしまいます。 いやしかし、マクロを使わないのが現代的なスタイルということは、覚えておきたいと思います。
SaitoAtsushi

2019/08/29 07:05

volatile か何かと混同していませんか? inline は最適化を抑制するのではなく、むしろ最適化のための機能でした。 (昔は。) C/C++ の inline 指定はインライン化する最適化 (関数を呼び出すのではなく内容をその場所に埋め込んでしまうことによって呼び出しのオーバーヘッドを抑制する) を当初は意図していたようです。 ただ、昔の C/C++ はそれぞれのコンパイル単位をコンパイルしてからリンクすることで実行ファイルを生成するという工程を踏みます。 なので、コンパイル時には他のコンパイル単位にどのような定義があるのか知ることが出来ません。 知ることができなければ内容を埋め込むことは出来ないので、 inline 指定する関数はそれを使う関数があるのと同じコンパイル単位にある必要がありました。 複数のコンパイル単位で同じインライン関数を使うならそれはヘッダファイルに書かなければいけなかったのです。 さて、 C/C++ では「同じ宣言を何度してもよいが定義はひとつしか許さない」というルール (one definition rule) があるのですが、 inline 指定を付けた関数はヘッダに書く機会があるのでプログラム全体で定義が複数存在してしまうことになります。 なので、インライン関数は one definition rule の例外ということになりました。 内容が同じであることという制約がありますが、インライン関数はプログラム全体の中で同じ定義を複数回書いてもかまいません。 この考え方の延長線上で、ヘッダファイルで定数を書くときにも (結果的に発生する) 定義の重複を許して欲しいというところから変数に inline 指定する機能が生まれました。 つまり、現在では inline というキーワードは「インライン化する」という意味ではなく「one definition rule の例外」という意味付けです。 ちなみに現代のモダンな C コンパイラは最適化にあたって inline 指定を無視するのが普通です。 効果的な最適化であると判断すれば指定があろうとなかろうとインライン化するので現代では最適化のヒント (インライン化の要請) として inline 指定をする意味は無いです。
torimingo

2019/08/29 12:50

思いっきり、volatileと混合していました、すみません。 昔と比べて、inlineの意味合いが変わっているのですね。 なかなか難しそうなので、時間のあるときに、実装して試してみたいと思います。
guest

0

こんにちは。

私は #define の方をよく使います。
下記のようにスムーズに結合できるので結構重宝しています。

C++

1#include <iostream> 2 3#define APP_NAME "FooApp" 4#define VERSION "1.0" 5 6int main() 7{ 8 std::cout << APP_NAME " v" VERSION; 9}

投稿2019/08/28 13:11

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/08/28 14:37

ご回答をありがとうございました。 参考になりました。#defineを使うことを少し強めに考えたいと思います。
guest

0

constexpr char str[] = "abc";

ではメモリ上にその領域が確保されますが、
define の方はそれはありません。

ましかし、そいつを何度も使う場合には、constexpr のほうはその領域(のアドレス)が使い回されるだけですが、
defineの方はその都度メモリに展開され、その結果無駄にメモリを使うことになります
#ましかし、最近のコンパイラは賢いので、一つの領域で済まされるってこともあったり

投稿2019/08/28 13:04

y_waiwai

総合スコア87784

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/08/28 14:39

ご回答をありがとうございました。 メモリを意識しなければいけない環境で開発するときに、参考にさせて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問