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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

5回答

1595閲覧

extern 変数の使い方

yukkuri_55

総合スコア240

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2021/10/10 02:02

編集2021/10/10 02:54

前提・実現したいこと

ヘッダーファイルに外部変数を置きたいのですが
externの使い方がいまいちわかっていません。
externはどうやって使うのでしょうか?

発生している問題・エラーメッセージ

1>------ ビルド開始: プロジェクト: 練習extern, 構成: Debug Win32 ------
1>コンパイルしています...
1>stdafx.cpp
1>コンパイルしています...
1>練習extern.cpp
1>マニフェストをリソースにコンパイルしています...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>リンクしています...
1>練習extern.obj : error LNK2005: "int * size" (?size@@3PAHA) は既に stdafx.obj で定義されています。
1>C:\Users\user\Documents\Visual Studio 2008\Projects\練習extern\Debug\練習extern.exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。
1>ビルドログは "file://c:\Users\user\Documents\Visual Studio 2008\Projects\練習extern\練習extern\Debug\BuildLog.htm" に保存されました。
1>練習extern - エラー 2、警告 0
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========

該当のソースコード

c

1// 練習extern.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 2// 3 4#include "stdafx.h" 5 6 7int _tmain(int argc, _TCHAR* argv[]) 8{ 9 printf( "size:%d\n", size[0]); 10 11 return 0; 12} 13
// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または // 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル // を記述します。 // #pragma once #include "targetver.h" #include <stdio.h> #include <tchar.h> // TODO: プログラムに必要な追加ヘッダーをここで参照してください。 #ifdef EXT extern int size[1] = {32}; #else int size[1] = {32}; #endif #define EXT

変更後

c

1// 練習extern.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 2// 3 4#include "stdafx.h" 5#define EXT 6#include "hoge.h" 7 8 9int _tmain(int argc, _TCHAR* argv[]) 10{ 11 printf( "size:%d\n", size[0]); 12 13 hogehoge(); 14 15 return 0; 16} 17

c

1#include "stdafx.h" 2#include "hoge.h" 3 4 5void hogehoge() 6{ 7 printf( "size:%d\n", size[0] ); 8}

c

1// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または 2// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル 3// を記述します。 4// 5 6#pragma once 7 8#include "targetver.h" 9 10#include <stdio.h> 11#include <tchar.h> 12 13 14 15// TODO: プログラムに必要な追加ヘッダーをここで参照してください。 16 17void hogehoge();

c

1 2 3#ifdef EXT 4int size[1] = {32}; 5#else 6extern int size[1]; 7#endif

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

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

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

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

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

guest

回答5

0

ヘッダファイルで変数宣言を行ったり、externの切り替えをおこなうってのはバグの温床になります
そんなところで手を抜くのはやめておいたほうがいいかと。

まあ、動けばそんでいいってことならいいでしょうけど

投稿2021/10/10 02:29

y_waiwai

総合スコア87774

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

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

itagagaki

2021/10/10 02:32

> ヘッダファイルで変数宣言を行ったり 定義、のことですよね
y_waiwai

2021/10/10 02:43

ああ、そうですね。補足ありがとうございます 自分だけがそのコードを扱うってならまあ、いいんでしょうけど、 他人のコードのメンテって時にこれが出てくると、そいつを締めたくなりますw
yukkuri_55

2021/10/10 02:48

ご指摘ありがとうございます。
guest

0

ベストアンサー

int size[1] = {32};は、「データを定義」します。
「データを定義」するとは、そのデータの現物を用意して、それ用の記憶域を割り当てることを意味します。

たとえば上記の定義をグローバル変数の定義としてヘッダファイルに書いてしまったとします。
そして、そのヘッダを a.c と b.c がそれぞれインクルードするとします。

インクルードというのは、そこに別のファイルの内容を取り込むだけですから、
a.c と b.c は、どちらも上記の定義を行ってしまうことになります。

a.c と b.c のコンパイルはできますが、この2つをリンクするとエラーとなります。
a.c と b.c の両方にグローバル変数sizeが存在し、重複してしまうからです。

ですので、グローバル変数の定義は、全体の中でどこか1カ所でなければなりません。
で、定義したデータを参照するためには「データの宣言」が必要になります。
それが extern int size[1]; です。
このexternは、「ストレージクラス指定子」と言って、「このデータは別のソースファイルで定義されているよ」という意味です。
externとして宣言された変数自体に記憶域は割り当てられません。
ただ参照するためだけの宣言になります。

提示されているヘッダファイルのコードでは、プリプロセッサマクロEXTが定義されているかによって、sizeの「定義」と「宣言」を切り替えているようです。
そのヘッダファイルをインクルードするCファイルのうち1つだけがプリプロセッサマクロEXTを定義することで、sizeを1つだけ定義するという策略だと思います。よく見るコードですが、この策略には賛否があると思います。

ところで

C

1extern int size[1] = {32};

これはよろしくありません。宣言のつもりなのに初期化子を指定しています。
上記のとおり、宣言はデータの現物を用意するものではありませんので、これは誤りです。
単に

C

1extern int size[1];

とすべきです。

投稿2021/10/10 02:25

編集2021/10/10 02:25
itagagaki

総合スコア8402

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

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

yukkuri_55

2021/10/10 02:49

丁寧な説明ありがとうございます。
guest

0

ヘッダファイルに#define EXTを書いてしまうのでは、せっかく上で#ifdefした意味がなくなります。

どこか1つのソースファイルでのみ有効化してください。あと、stdafx.hは変化しないシステムヘッダーを入れるのが前提のファイルなので、自作の定義を入れるには適切な場所ではありません。

C

1// variables.c 2 3#define EXT 4#include "hoge.h"

投稿2021/10/10 02:19

編集2021/10/10 02:23
maisumakun

総合スコア145183

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

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

yukkuri_55

2021/10/10 02:50

maisumakunさんのやるやり方で やってみようかと思います。 修正したのを編集にてあげておきます。 ありがとうございます。
guest

0

c

1--main.cpp-- 2#define ETN 3#include "global.h" 4printf( "size:%d\n", size );

c

1--global.h-- 2#ifdef ETN 3 int size = 32; 4#else 5extern int size; 6#endif

c

1--other.cpp-- 2#include "global.h" 3printf( "size:%d\n", size );

投稿2021/10/11 00:58

yukkuri_55

総合スコア240

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

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

0

関数だとヘッダで宣言し、C-codeのどれか一つに定義するでしょ? 変数でも同じです。

C

1// sub.h 2extern int global_value;

C

1// sub.c 2#include "sub.h" 3int global_value;

投稿2021/10/10 03:42

編集2021/10/10 03:43
episteme

総合スコア16614

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問