型の二重宣言 【C言語の相談】

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

型の二重宣言 【C言語の相談】

#1

投稿記事 by HK » 14年前

こんにちは。 以前に以下のようなことがあって悩んでいたので質問させていただきます。

Cの話です。

大学で、ある研究分野で世界的に有名なオープンソースを動かして見ようと思い、ダウンロードしたのちにコンパイルしました。
すると、以下のようなコンパイルエラーが出ました。(Ubuntu11.10のgcc、Cygwinのgccの2通りを試しましたが結果は同じでした。)

fileio.h:69:7 error:conflicting types for 'getline'
/なんたらかんたら/stdio.h:37:9: note: previous declaration of 'getline' was here

すなわち、型の2重宣言ですね。
stdio.hに既に宣言されている型を、別のfileio.hというヘッダファイルで宣言してしまっている と私は解釈しました。

確かに、 fileio.h というヘッダファイルの中身を見てみると、69行目に getline という型を宣言している部分がありました。
この2重宣言を回避するために、私はfileio.h と他の「'getline'型を使っているファイル」の全てにおいて、「getline」を「getline42」のように置換しました。
その後、再度コンパイルしてみると、無事通り、プログラムも問題なく動きました。


・・・と、いうわけで、「問題を解決してほしい!」という類の質問ではないのですが、疑問に思ったことを相談させてください。


①世界的に有名であるオープンソースであるにも拘わらず、C言語標準ライブラリのstdio.hに含まれる型を使ってしまっているというミスは何故起きたのでしょうか。

②このような型の2重宣言をしてしまっているソースコードを直したい場合、私が行なった上記のような方法は良い方法と言えるでしょうか? (一気に置換しましたが、cファイルが多くてとてもめんどくさかったw) 他に良い方法はありませんか?


ちなみに そのオープンソースとは、SOM_PAK  というもので、ここで手に入ります。
http://www.cis.hut.fi/research/som-rese ... rams.shtml

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#2

投稿記事 by beatle » 14年前

getline関数はもともとGNU拡張の関数でしたが、最近POSIXになったようです。
参考http://linuxjm.sourceforge.jp/html/LDP_ ... ine.3.html

http://www.cis.hut.fi/research/som_pak/
から入手できるSOM_PAKは古いものですので、POSIXにgetlineがないころのものです。

SOM_PAKのドキュメントにもかかれている通り、このソフトは元々Unix向けに
作られており、GNU環境(GCC+glib)でコンパイルされることを意図されていない
と思われます。
①世界的に有名であるオープンソースであるにも拘わらず、C言語標準ライブラリのstdio.hに含まれる型を使ってしまっているというミスは何故起きたのでしょうか。
getlineは純粋なCの標準関数ではないからです。
ためしに/usr/include/stdio.hを見てみましょう。getlineのプロトタイプ宣言は
#if __USE_XOPEN2K8
#endif
で囲まれています。
②このような型の2重宣言をしてしまっているソースコードを直したい場合、私が行なった上記のような方法は良い方法と言えるでしょうか? (一気に置換しましたが、cファイルが多くてとてもめんどくさかったw) 他に良い方法はありませんか?
コンパイル時にANSI-Cモードでコンパイルすれば解決します。
makefileのCFLAGSに

コード:

CFLAGS = -O -ansi
というふうに -ansi を追加してmakeしましょう。

komachi
記事: 5
登録日時: 14年前
住所: Hyogo
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#3

投稿記事 by komachi » 14年前

早速のご回答、また、本家のドキュメントの方まで見ていただいてありがとうございます!

なんかユーザー登録できたので、名前が変わってますが、私は質問者と同一人物です。

①の方は、理解することができました。確かに、このソースは90年代のもので、かなり古いですね。

②のほうですが、
ANSI-Cモードでコンパイルするためにmakefileを書き換えましたが
以前と同様のエラーが出ました。

具体的には、

コード:

CFLAGS = -O
となっている箇所を

コード:

CFLAGS = -O -ansi
と変更しました。

ANSI-Cモードというのがイマイチわかっていないのに加え、makefileの書き方すらあまり知らないので(笑)、何をやっているのかわかっていません。
これからmakefileの書き方と、ANSI-Cについて少し勉強してみます。

もしよろしければ、ANSI-Cについて簡単にご教示ください

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#4

投稿記事 by beatle » 14年前

komachi さんが書きました: ②のほうですが、
ANSI-Cモードでコンパイルするためにmakefileを書き換えましたが
以前と同様のエラーが出ました。

具体的には、

コード:

CFLAGS = -O
となっている箇所を

コード:

CFLAGS = -O -ansi
と変更しました。

ANSI-Cモードというのがイマイチわかっていないのに加え、makefileの書き方すらあまり知らないので(笑)、何をやっているのかわかっていません。
これからmakefileの書き方と、ANSI-Cについて少し勉強してみます。

もしよろしければ、ANSI-Cについて簡単にご教示ください
あら、僕がUbuntu10.04 + gcc 4.6で試したときはうまく行きましたが。
makefileはmakefile.unixを改名したもので、中身は

コード:

CC=cc
CFLAGS=-O -ansi
LDFLAGS=-s
LDLIBS=-lm
LD=$(CC)
となっています(コメントアウトしてある部分は省略しています)。


ANSI-CというのはC言語の規格の名前ですね。
一口にC言語と言っても、様々な規格があるのです。まあ歴史も長いですからね。
そのへんの話はANSI-Cも含めてhttp://ja.wikipedia.org/wiki/C%E8%A8%80%E8%AA%9Eが役立つと思います。

komachi
記事: 5
登録日時: 14年前
住所: Hyogo
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#5

投稿記事 by komachi » 14年前

ご回答頂きありがとうございます。
C言語の規格の記事を読みました。 
-ansiとは、C89規格でコンパイルするときに使うんですね。

ところで、色々なサイトを見ていたら、同じような問題に関して言及してあるページが見つかりました。
yahoo!知恵袋
http://chiebukuro.spn.yahoo.co.jp/detail/q1260494702

今、ubuntuが使える環境にいなくて、先程のmakeはcygwinでやりました。
上のページに書いているように、cygwinに関しては
「/usr/include/stdio.h から /usr/include/sys/stdio.h の取り込み命令があり、そこに getline() の ifdef で保護された宣言がある」
ので、実際にsys/stdio.hの中を見てみると、

確かに

コード:

#ifndef _SYS_STDIO_H_
 ・・・
#endif
で囲まれている宣言が見つかりました。 この部分さえ外してしまえば getline() の2重宣言を回避することができると思うのですが、いかがでしょう?

とはいえ、stdio.h本体を書き換えるというのは 良い方法とは言えませんよね。
こういう場合、どうすれば上記の部分を外してコンパイルすることが可能ですか?
なんか本質を理解せずに枝葉末節な質問をしている気がしますがご教示願います。

ちなみに、知恵袋には、「getline()を違う名前に置換する」 という、私がとった方法も 対処例のひとつとして挙げられていました。
置換の回数があまり多くない場合は、この方法でも十分かなと思いました。

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#6

投稿記事 by beatle » 14年前

komachi さんが書きました:今、ubuntuが使える環境にいなくて、先程のmakeはcygwinでやりました。
上のページに書いているように、cygwinに関しては
「/usr/include/stdio.h から /usr/include/sys/stdio.h の取り込み命令があり、そこに getline() の ifdef で保護された宣言がある」
ので、実際にsys/stdio.hの中を見てみると、

確かに

コード:

#ifndef _SYS_STDIO_H_
 ・・・
#endif
で囲まれている宣言が見つかりました。 この部分さえ外してしまえば getline() の2重宣言を回避することができると思うのですが、いかがでしょう?

とはいえ、stdio.h本体を書き換えるというのは 良い方法とは言えませんよね。
こういう場合、どうすれば上記の部分を外してコンパイルすることが可能ですか?
なんか本質を理解せずに枝葉末節な質問をしている気がしますがご教示願います。

ちなみに、知恵袋には、「getline()を違う名前に置換する」 という、私がとった方法も 対処例のひとつとして挙げられていました。
置換の回数があまり多くない場合は、この方法でも十分かなと思いました。
ははあ、もしかしたらcygwinのstdio.hは、-ansiオプションを付けようが付けまいが、getlineのプロトタイプ宣言が有効になってしまう仕様のようですね。
その場合は仕方ないですから、getlineを違う名前にする、という対処方にならざるを得ませんね。

その場合、各ファイルを手動で置換するのは面倒ですよね。
大丈夫、すべてのファイルを自動で置換することなんか簡単ですから。

http://blog.livedoor.jp/leaf_hiro/archi ... 81124.html
こんな感じで、findとperlを組み合わせれば、特定のディレクトリ以下すべてのファイルに対して一気に置換できます。
(すみません。cygwinで実行できるかは未確認です。findコマンドとperlコマンドが有れば出来るとは思いますが。)

komachi
記事: 5
登録日時: 14年前
住所: Hyogo
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#7

投稿記事 by komachi » 14年前

beatle さんが書きました:その場合、各ファイルを手動で置換するのは面倒ですよね。
大丈夫、すべてのファイルを自動で置換することなんか簡単ですから。

http://blog.livedoor.jp/leaf_hiro/archi ... 81124.html
こんな感じで、findとperlを組み合わせれば、特定のディレクトリ以下すべてのファイルに対して一気に置換できます。
おお! なんと。素晴らしいことを教えていただきました。ありがとうございます。
beatle さんが書きました:(すみません。cygwinで実行できるかは未確認です。findコマンドとperlコマンドが有れば出来るとは思いますが。)
cygwinでも無事にできました。この方法で置換してコンパイルしたものも、もちろん正しく動作しました。ありがとうございます。
 

たかぎ
記事: 328
登録日時: 15年前
住所: 大阪
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#8

投稿記事 by たかぎ » 14年前

こんな風にすれば、stdlib.hの中のgetlineを別名にすり替えられませんか?

コード:

/* stdio.h */
#ifndef WRAPPER_STDIO_H
#define WRAPPER_STDIO_H

#define getline  getline_rename
#include_next <stdio.h>
#undef getline_rename /* ← 間違っていたので修正 */

#endif  /* !WRAPPER_STDIO_H */
上のようなstdlib.hを作成し、そのファイルがあるディレクトリを-Iオプションで指定しておけばよいかと思います。
最後に編集したユーザー たかぎ on 2011年11月11日(金) 21:09 [ 編集 1 回目 ]

komachi
記事: 5
登録日時: 14年前
住所: Hyogo
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#9

投稿記事 by komachi » 14年前

たかぎさんご回答頂きありがとうございます。
その方法でgetline()の名前をすり替えることに成功しました。

ところで、getline()が宣言されているところを直接変更する、例えば、

コード:

#define getline  getline_rename

( getlineの宣言 )

#undef getline
のように挟みこむはダメなのでしょうか?

たかぎ
記事: 328
登録日時: 15年前
住所: 大阪
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#10

投稿記事 by たかぎ » 14年前

komachi さんが書きました:ところで、getline()が宣言されているところを直接変更する、例えば、

コード:

#define getline  getline_rename

( getlineの宣言 )

#undef getline
のように挟みこむはダメなのでしょうか?
それでもすり替わりますが、オリジナルのstdio.hを破壊することになります。
私が書いた方法(一部間違っていたので修正しましたが...)なら、非破壊で対応できます。

komachi
記事: 5
登録日時: 14年前
住所: Hyogo
連絡を取る:

Re: 型の二重宣言 【C言語の相談】

#11

投稿記事 by komachi » 14年前

ご回答頂きありがとうございます。
たかぎ さんが書きました:私が書いた方法(一部間違っていたので修正しましたが...)なら、非破壊で対応できます。
なるほど。

修正点も含め、全て納得いきました。
皆様ご協力頂き、本当にありがとうございました。

閉鎖

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