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

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

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

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

コンパイル

コンパイルとは、プログラミング言語のテキストソース(ソースコード)をコンピュータ上で実行可能な形式(オブジェクトコード)に変換することをいいます

Q&A

解決済

4回答

6175閲覧

C言語で分割コンパイルを行いたいのですが、「外部シンボル '_count1' が未解決」とエラーが出てコンパイル出来ません

tada_tadaa

総合スコア111

C

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

コンパイル

コンパイルとは、プログラミング言語のテキストソース(ソースコード)をコンピュータ上で実行可能な形式(オブジェクトコード)に変換することをいいます

0グッド

0クリップ

投稿2016/02/15 06:42

編集2016/02/15 06:48

お世話になっております。
C言語で分割コンパイルを行いたいのですが、エラーが出て
しまいます。コンパイラーはBorland C++ 5.5.1です。
ソースファイルはmain.cとch11-02.c.cの二つです。
以下にソースファイルの内容を載せます。

↓main.c

c

1#include <stdio.h> 2#include "ch11-02.c.c" 3 4int main(void) 5{ 6 int i; 7 8 f1(); // カウントの値を設定する 9 10 for(i=0; i<count1; i++) 11 printf("%d ", i); 12 13 return 0; 14}

↓ch11-02.c.c

c

1#include <stdlib.h> 2 3extern int count1; 4void f1(void); 5 6void f1(void) 7{ 8 count1 = 10; 9 //printf("f1 \n"); 10}

コマンドプロンプトで
bcc32 -c main.c
bcc32 -c ch11-02.c.c
を実行します。するとmain.objとch11-02.c.objが
作成されます。次に、
bcc32 main.obj ch11-02.c.obj
を実行すると次のようにエラーが表示されます。

Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
Error: 外部シンボル '_count1' が未解決(C:\DOCUMENTS AND SETTINGS\TADA_J72_2\LOC
AL SETTINGS\APPLICATION DATA\EASYIDEC\PROJECT\CH11-01.C\MAIN.OBJ が参照)
Warning: パブリックシンボル f1 がモジュール C:\DOCUMENTS AND SETTINGS\TADA_J72
2\LOCAL SETTINGS\APPLICATION DATA\EASYIDEC\PROJECT\CH11-01.C\MAIN.OBJ と C:\DOCU
MENTS AND SETTINGS\TADA_J72_2\LOCAL SETTINGS\APPLICATION DATA\EASYIDEC\PROJECT\C
H11-01.C\CH11-02.C.OBJ の両方に定義されている

'_count1' が未解決とエラーが出て困っています。
プログラム文が悪いのか、コンパイルの仕方が悪いの
か分かりません。
ちなみにcount1という変数を消して、ch11-02.c.cの
f1関数でprintf文を実行するだけにしたら、一応
コンパイルできて実行ファイルができました。

どなたかお分かりの方がいれば教えていただければと
思います。

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

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

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

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

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

coco_bauer

2016/02/15 06:49

main.c に 「for(i=0; i<count1; i++)」という行がありますが、ここで使われているcount1がmain.cの中で宣言されていません。ここに問題があるのではないでしょうか。
tada_tadaa

2016/02/15 09:24

ご回答ありがとうございます。 count1をmain.cの中で宣言したらとりあえずコンパイルできました。 externの使い方をよく分かってませんでした。 ありがとうございました。
guest

回答4

0

2点間違いがあります。

まず、main.c でch11-02.c.c をincludeしているので、main.c は下記と同じです。

C

1#include <stdio.h> 2#include <stdlib.h> 3 4extern int count1; 5void f1(void); 6 7void f1(void) 8{ 9 count1 = 10; 10 //printf("f1 \n"); 11} 12int main(void) 13{ 14 int i; 15 16 f1(); // カウントの値を設定する 17 18 for(i=0; i<count1; i++) 19 printf("%d ", i); 20 21 return 0; 22}

includeというのは、コンパイル前にソースを取り込むことです。
従って、このままのプログラムだと、main.c と別に ch11-02.c.c をコンパイルするのは無意味です。

2番目は、extern というのは、「他のコンパイル単位で、グローバル変数定義しているよ」という意味です。
従って、どこかのソースで、int count1;というグローバル変数定義が必要。これが無いために未定義エラーになっています。

main.cをこういう風にすればいいかと思います。

C

1#include <stdio.h> 2int count1; 3void f1(void); 4 5int main(void) 6{ 7 int i; 8 9 f1(); // カウントの値を設定する 10 11 for(i=0; i<count1; i++) 12 printf("%d ", i); 13 14 return 0; 15}

あと、ch11-02.c.c のf1のプロトタイプ宣言が不要。

投稿2016/02/15 07:11

otn

総合スコア84555

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

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

tada_tadaa

2016/02/15 09:01

ご回答ありがとうございます。 >includeというのは、コンパイル前にソースを取り込むことです。 従って、このままのプログラムだと、main.c と別に ch11-02.c.c をコンパイルするのは 無意味です。 たしかに次のようなプログラム文でコンパイルできました。 //main.c #include <stdio.h> int count1; void f1(void); #include "ch11-02.c.c" int main(void) { int i; f1(); // カウントの値を設定する for(i=0; i<count1; i++) printf("%d ", i); return 0; } //ch11-02.c.c #include <stdlib.h> extern int count1; void f1(void) { count1 = 10; } ↑これでコマンドプロンプトで bcc32 main.c を実行すればうまく実行ファイルができました。 ようするに#includeとはotnさんがおっしゃるように、その位置に別のファイル内容を 取り込んでいるということだと分かりました。だから上記のようにしてやれば分割コ ンパイルしなくても普通のコンパイルで出来ると分かりました。 まだ、分割コンパイルと普通のコンパイルの適切な使い分けがよくわかってないよう なので適切な使い分けが出来ればいいなと思っています。 また、extern int count1; というのは他の場所に int count1が定義されていますよ という宣言のようなものなので、他のファイルに int count1を定義しないといけない ということも理解できました。 ご回答ありがとうございました。
guest

0

こんにちは。

2点の混乱があるようです。

まず、#includeは単純にその位置へ指定ファイルの中身を展開するものです。
ですので、main.cで#include "ch11-02.c.c"すると、main.cで関数f1()の実体が定義されてしまいます。
そして、ch11-02.c.cをコンパイルしたobjファイルにも当然f1()の実体が定義されてます。
従って、main.objとch11-02.c.objの両方にf1()の実体が含まれますので、パブリックシンボル _f1 が(中略) の両方に定義されているエラーがでます。
分割コンパイルする場合、main.cで#include "ch11-02.c.c"しないことが一般的です。

次に、count1の実体が定義されていません。externをつけた場合、実体を定義せずアクセスできるようにする宣言となります。
main.cかch11-02.c.cのどちらかで、実体を定義(int count1;)し、定義しなかった方でexternを付けて宣言すると良いです。

投稿2016/02/15 07:10

Chironian

総合スコア23272

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

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

tada_tadaa

2016/02/15 08:34

ご回答ありがとうございます。 C言語の本を読んでてソースファイルが二つの例が出てきて、externの使い方が載ってた ので実際にコンパイルしてみたいと思ったのが事の始まりでした。分割コンパイルもやっ たことがなく、なにか頭が混乱しているようです。 Chironianがおっしゃるように、main.cで#include "ch11-02.c.c"をコメントアウトして int count1; を記述して、コマンドラインから bcc32 -c ch11-02.c.c bcc32 -c main.c bcc32 main.obj ch11-02.c.obj とやると実行ファイルがエラーが出ずにできました。(警告は出ましたが) >count1の実体が定義されていません。externをつけた場合、実体を定義せずアクセスで きるようにする宣言となります。 extern int count1;を一か所記述すればほかのファイルでも参照できるものと思ってまし たがそうではなく、externとはなにかその変数がほかの場所にありますよという宣言のよ うなものだと理解しました。だからほかのファイルにその宣言通りに、その変数がないと ダメなのだと理解しました。 ご回答ありがとうございました。
guest

0

ベストアンサー

extern宣言は、「どこか別の場所でその変数が定義されているものを使う」という宣言です。どこかでexternなしで変数を作成する必要があります。

なお、グローバル変数が多くなる場合、変数定義専用のソースコードを作っておいて、

C

1/* グローバル変数用のヘッダファイル globals.h */ 2#ifdef IMPLEMENT 3#define EXTERN /* 抹消 */ 4#else 5#define EXTERN extern 6#endif 7 8EXTERN int count1; 9 10/* 変数定義用のソースファイル */ 11 12#define IMPLEMENT 13#include "globals.h"

のように、1ファイルでexternの有無に両対応させる、という技があります。

投稿2016/02/15 06:59

maisumakun

総合スコア145184

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

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

tada_tadaa

2016/02/15 09:48

ご回答ありがとうございます。 僕はてっきり、一つのextern int count1; で他のファイルでも参照できるものと思ってました。 しかし、externはあくまで「他の変数を使いますよ」という宣言で、それ自体で変数の実体を 宣言しているわけではないということが分かりました。だから、extern int count1; とは別に int count1; を別のファイルに宣言しないといけないということが分かりました。 >のように、1ファイルでexternの有無に両対応させる、という技があります。 便利な技を教えていただいてありがとうございます。 独習Cの359ページに #if #else #endif などが載ってまして、そこまで読み進めておりません が読み終わったら、またmaisumakunさんの技を調べてみようと思います。 ご回答ありがとうございました。
guest

0

main.cで#include "ch11-02.c.c" とcのソースを取り込んでいるのはなぜでしょう?
上記の行をコメントアウトしてmain.c側でint count1;の宣言をすれば
bcc32 main.c ch11-02.c.c で出来ませんか?

投稿2016/02/15 07:15

cateye

総合スコア6851

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

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

tada_tadaa

2016/02/15 09:13

ご回答ありがとうございます。 >#include "ch11-02.c.c" とcのソースを取り込んでいるのはなぜでしょう? すみません、僕が分割コンパイルに無知なため訳も分からずつけていました。 cateyeさんがおっしゃるようにmain.cで#include "ch11-02.c.c"をコメントアウトして main.c側でint count1;の宣言をすれば bcc32 main.c ch11-02.c.c で出来ました。 ご回答ありがとうございました。
cateye

2016/02/15 09:55

グローバル変数(関数外で宣言された変数:今回はint count1)の使用は推奨されません。小さなプログラムだと気にはならないと思いますが、大きなプログラムだとバグの温床になりやすいです。また、(どこからでも書き換えが出来てしまうので)バグの発見が難しくなります。出来るだけ戻り値(returnで返された)を受け取るようにしましょう。 「関数」http://www9.plala.or.jp/sgwr-t/c/sec11.html
tada_tadaa

2016/02/15 12:15

>バグの温床になりやすいです。また、(どこからでも書き換えが出来てしまうので)バグの発見が難しくなります。 そうなんですか。参考になります。 cateyeさんが教えてくださったサイトも参考にして以下のよ うに書き改めてみました。 main.c #include <stdio.h> int main(void) { int i; int count1; count1 = f1(); // カウントの値を設定する for(i=0; i<count1; i++) printf("%d ", i); return 0; } ch11-02.c.c int f1(void); int f1(void) { int z; z = 10; return z; }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問