2

私は少し困惑しています。コンパイルするプロジェクトがあります

CFLAGS=-g -O2 -Wall -Wextra -Isrc/main -pthread -rdynamic -DNDEBUG $(OPTFLAGS) -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=700

今、私は使用したいmkdtempので、含めますunistd.h

char *path = mkdtemp(strdup("/tmp/test-XXXXXX"));

MacOSX では、コンパイルでいくつかの警告が表示されます

warning: implicit declaration of function ‘mkdtemp’
warning: initialization makes pointer from integer without a cast

しかし、コンパイルは通ります。NULL 以外のパスにアクセスすると、 EXC_BAD_ACCESSmkdtempが返されます。

質問 1: テンプレートがstrdup()ed で、結果が非​​ NULL です。いったいどうしてこれが EXC_BAD_ACCESS になるのでしょうか?

ウサギの穴をさらに下ります。警告を取り除きましょう。チェックunistd.hすると、プリプロセッサによって隠されている宣言が見つかりました。

#if     !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
...
char    *mkdtemp(char *);
...
#endif

ビルドに追加-D_DARWIN_C_SOURCEすると、すべての問題が解消されますが、プラットフォーム固有のビルドが残ります。10.6のマニュアルページには、

 Standard C Library (libc, -lc)
 #include <unistd.h>

ビルドメイクからの削除は_XOPEN_SOURCEOSXでは機能しますが、Linuxではコンパイルに失敗します

warning: ‘struct FTW’ declared inside parameter list
warning: its scope is only this definition or declaration, which is probably not what you want
In function ‘tmp_remove’:
warning: implicit declaration of function ‘nftw’
error: ‘FTW_DEPTH’ undeclared (first use in this function)
error: (Each undeclared identifier is reported only once
error: for each function it appears in.)
error: ‘FTW_PHYS’ undeclared (first use in this function)

質問 2: では、これをどのように修正しますか?

私が見つけた唯一の修正は、#undefインクルードの直前に _POSIX_C_SOURCE するunistd.hことです...しかし、それは醜いハックのように感じます。

4

2 に答える 2

2

あなたはここで 2 つの質問をしましたが、私は最初の質問にだけ答えます。

質問 1: テンプレートは strdup() され、結果は非 NULL です。いったいどうしてこれが EXC_BAD_ACCESS になるのでしょうか?

上記の警告が示すように:

警告: 関数 'mkdtemp' の暗黙の宣言</p>

これは、 の宣言が見つからなかったことを意味しmkdtempます。C の規則では許可されていますが、関数が int を返すことを前提としています。

警告: 初期化により、キャストなしで整数からポインターが作成されます

あなたはコンパイラに「int を返す関数があり、その値を char* に格納したい」と伝えました。これは悪い考えだと警告しています。あなたはまだそれを行うことができるので、コンパイルされます。

しかし、実行時に何が起こるか考えてみてください。リンク先の実際のコードは、64 ビットの char* を返します。次に、コードはそれを 32 ビット int として扱い、64 ビット char* にキャストする必要があります。それが機能する可能性はどれくらいですか?

これが、警告を無視しない理由です。

于 2012-07-11T23:57:21.067 に答える
0

次に、2 番目の質問について説明します。

質問 2: では、これをどのように修正しますか?

あなたの問題は、明示的に -D_XOPEN_SOURCE=700 を渡しているが、要求している標準で定義されていない関数 mkdtemp を使用していることです。つまり、コードが機能しないはずです。Linux で動作するという事実は、あなたのコードが正しいとか移植可能であるという意味ではなく、たまたま 1 つのプラットフォームで運が良かったということです。

したがって、これを修正するには、かなり明白な方法が 2 つあります。

  1. _XOPEN_SOURCE=700 を使用する場合は、その標準にある関数のみを使用するようにコードを書き直してください。

  2. _XOPEN_SOURCE=700 をハックとして追加しただけで、Linux の他の問題を解決しているように見えてよくわからない場合は、Linux でその問題を解決する正しい方法を見つけてください。

あるプラットフォームまたは別のプラットフォームにバグがあることが判明する可能性があるため、それを修正する正しい方法はありません. または、より可能性が高いのは、それぞれに異なるフラグのセットを使用して、異なるプラットフォームで絞り込むことができる非標準関数の組み合わせを使用しているということです。その場合、Makefile (またはビルドを駆動するもの) は、異なるプラットフォームのコンパイラに異なるフラグを渡す必要があります。これは、クロスプラットフォーム プロジェクトではよくあることです。心配するフラグが 1 つしかなく、3000 行分の autoconf を構築していないことを嬉しく思います。

于 2012-07-12T00:02:52.247 に答える