C言語での構造体の定義と初期化
こんにちは。
C言語での構造体の定義と初期化について質問させてください。
現在、ファイル操作に関する自作ライブラリをいじっており、その中でファイルのパス名を分解する関数を作成しました。
関数自体は出来上がっており、リンクさせて動作テストをしているのですが、コンパイラが各オブジェクトをコンパイルしているときに警告が発生し、どうやっても解消しません。
gccはエラーを吐いて、コンパイルはしてもリンクしてくれません。
Bccでは警告だけで無理矢理リンクしているようですが、何故か実行ファイルが494 KB、通常の4倍以上のサイズに肥大してしまいます(コマンドラインツールなので通常は大きくても100KB程度)。
警告の原因と対処について、どなたかアドバイスをお願いします。
以下状況を簡単に説明します。
開発環境は、
PC:WinXP sp3
開発環境1:「Borland C++ compiler 5.5.1」 「MAKE Version 5.2」
開発環境2:「gcc version 3.4.5 (mingw special)」 「GNU Make version 3.79.1」
です。各環境につきMAKEFILEがあり、どちらでもコンパイルできるようにしてあります。
ヘッダファイルは長いので、全体は後で貼り付けますが、問題となっているのは多分次の部分です。
構造体のメンバとして6種類の文字配列をもち、この中にパス名やファイル名などを格納します。
struct st_split_path{
char drive [MAX_FULLPATH];//ドライブ名
char dirpath[MAX_FULLPATH];//ディレクトリパス
char dir [MAX_FULLPATH];//直属のディレクトリ名
char fname [MAX_FULLPATH];//ファイル名
char fname2 [MAX_FULLPATH];//ファイル名(拡張子抜き)
char ext [MAX_FULLPATH];//拡張子(ドットつき)
int buffsize;
} st_split_path = {
{'\0'},
{'\0'},
{'\0'},
{'\0'},
{'\0'},
{'\0'},
MAX_FULLPATH,
};
typedef struct st_split_path SPLIT_PATH;
きちんと初期化された構造体を宣言した後、typedefで新しい型として定義しています。
初期化しないなら宣言は
typedef struct SPLIT_PATH{
char drive [MAX_FULLPATH];//ドライブ名
char dirpath[MAX_FULLPATH];//ディレクトリパス
char dir [MAX_FULLPATH];//直属のディレクトリ名
char fname [MAX_FULLPATH];//ファイル名
char fname2 [MAX_FULLPATH];//ファイル名(拡張子抜き)
char ext [MAX_FULLPATH];//拡張子(ドットつき)
int buffsize;
} SPLIT_PATH;
とするところですが、文字配列が6つもあるので、初期化を予めしておきたいと考えた次第です。
これで次のようなエラー(警告)が出ます。
Bcc
Warning: パブリックシンボル _st_split_path がモジュール E:\WORK\FILE_CMP.OBJ と
E:\WORK\LIB-FILE.OBJ の両方に定義されている
gcc
Lib-file.obj:Lib-file.c:(.data+0x0): multiple definition of `st_split_path'
File_cmp.obj:File_cmp.c:(.data+0x0): first defined here
多分、ヘッダを取り込んだ先でそれぞれ宣言されてリンク時に名前がかち合っているのだと推察できますが、理由がよく分かりません。
これはあくまで構造体定義で、実体は呼び出し側で
SPLIT_PATH sppath;
として宣言していると考えています。
また、ヘッダファイル自体は多重インクルードガードをかけていますので、別のヘッダがこいつを再度取り込んでいるとは考えられません。
また、何らかの原因で実体を持っているのなら、extern 宣言で解決できると思い、
} st_split_path = {
を
} extern st_split_path = {
ともしてみましたが状況は変わりませんでした。
私がexternを理解できていないだけかもしれませんが、他に解決策は思いつきません。
もしかして定義と初期化は同時にはできないのでしょうか。
google検索で「C言語 構造体 定義と同時に初期化」と検索しても、一応できるとは書いてあるのですが、サイトによって構造体宣言と定義が区別されてないようなサイトもあり、よく分かりません。
どなたかご教授ください。
長いのですが、次に問題があるであろうヘッダファイルの抜粋を載せておきます。
ヘッダ"Lib-file.h"の抜粋です。
問題ない構造体宣言や、雑多な関数宣言以外は、マクロ定義を含めそのままです。
#ifndef Lib_file_h
//自分自身の定義
#define Lib_file_h
#include "Lib-macro.h"
/****************************************************************/
/**************** 環境依存につきifdef条件include ****************/
/****************************ここから****************************/
#ifdef __GNUC__
#include <sys/utime.h>
#endif
#ifdef _MSC_VER
#include <sys/utime.h>
#endif
#ifdef __BORLANDC__
#include <utime.h>
#endif
#ifdef __INTEL_COMPILER
#include <sys/utime.h>
#endif
/****************************ここまで****************************/
/**************** 環境依存につきifdef条件include ****************/
/****************************************************************/
#include <time.h>
#include <sys/stat.h>
#include <io.h>
#include <fcntl.h>
#define MAX_FULLPATH (255*128)
struct st_split_path{
char drive [MAX_FULLPATH];//ドライブ名
char dirpath[MAX_FULLPATH];//ディレクトリパス
char dir [MAX_FULLPATH];//直属のディレクトリ名
char fname [MAX_FULLPATH];//ファイル名
char fname2 [MAX_FULLPATH];//ファイル名(拡張子抜き)
char ext [MAX_FULLPATH];//拡張子(ドットつき)
int buffsize;
} st_split_path = {
{'\0'},
{'\0'},
{'\0'},
{'\0'},
{'\0'},
{'\0'},
MAX_FULLPATH,
};
typedef struct st_split_path SPLIT_PATH;
#ifdef __cplusplus
extern "C" {
#endif
time_t file_mtime_get(char *fname);
int split_path(char *fullpath,SPLIT_PATH *sppath);
int fpath_regularization(char *fullpath);
#ifdef __cplusplus
};
#endif
#endif
お礼
回答ありがとうございます。 少し制限があることが分かりました。 ということは、関数内に書いたり命令の直後に書いても動作上は問題ないと言うことですか? ............. #define kazu 200 if(!(.....)) printf("kazu\n"); #define kazu 100 printf("kazu"); .............. (...は省略の意味) このような記述は危険ではないのでしょうか?