LinuxとWindowsでコンパイルできる必要があるCプログラムでこの関数を使用しようとしています。最初はstrtok_rを使用しようとしましたが、Windowsでコンパイルすると、関数が存在しないと文句を言い、extern関数であると想定すると表示されましたが、失敗しました。次に、strtok_sを使用してコンパイルしました!次にLinuxを試してみましたが、「strtok_s 'への未定義の参照」があると文句を言っています。
1つはWindows専用の機能で、もう1つはLinuxの機能ですか?両方でコンパイルするにはどうすればよいですか?
これらの関数はどちらも、文字列を解析するための非常に醜く直感的でないイディオムであり、通常、特定のアプリケーションの要件を微妙に満たすことができません。標準Cの単純なstrtok
の場合はさらにそうです。それらを破棄して独自のコードを記述し、char
配列を反復処理して、必要に応じて分割します。 strchr
、strspn
、およびstrcspn
は、これを行うのに役立つ場合があります。または、配列を最初から作成することもできます。
strtok_s
は、他のすべての場所で標準となっているstrtok_r
のWindowsバージョンです。
strtok_s
/strtok_r
のような関数に関してプログラムを移植可能にする1つの(私が思うと思う)方法は、プリプロセッサを使用することです。
#if defined(_WIN32) || defined(_WIN64)
/* We are on Windows */
# define strtok_r strtok_s
#endif
プロトタイプと機能は同じであるため、strtok_r
のみを使用できるようになりました。
他の回答についてコメントするのに十分な評判がないので、自分で回答する必要があります。
1)このステートメントに対処するには:
「strtok_sは、Windowsのstrtokのバッファオーバーランセーフバージョンです。Windowsの標準のstrtokはスレッドセーフです...」
本当じゃない。 strtok_sは、MSVCコンパイラのスレッドセーフバージョンです。 strtokはスレッドセーフではありません!
2)このステートメントに対処するには:
「自分自身をウィンドウとして報告するが、
strtok_r
のようなPOSIXインターフェースがすでに定義されているCygwinでコンパイルすると、これはおそらく壊れます。」
繰り返しますが、真実ではありません。違いは、使用するコンパイラです。 MicrosoftのVisualC++コンパイラであるMSVCを使用する場合、関数はstrtok_s.
です。GNUコンパイラコレクション、GCCなどの別のコンパイラは、strtok_r
などの別の標準ライブラリ実装を使用する場合があります。プラットフォーム、使用する機能を識別するとき。
私の意見では、ヨアヒム・ピレボルグの答えはこのページで最高のものです。ただし、少し編集する必要があります。
#if defined(_WIN32) /* || defined(_WIN64) */
#define strtok_r strtok_s
#endif
_WIN32と_WIN64はどちらも、MSVCコンパイラによって提供される定義済みマクロです。 _WIN64は、64ビットターゲットをコンパイルするときに定義されます。 _WIN32は、32ビットと64ビットの両方のターゲットに対して定義されています。これは、Microsoftが下位互換性のために作成した妥協案です。 _WIN32は、Win32APIを指定するために作成されました。ここで、WindowsAPIを指定するために_WIN32を検討する必要があります。これは32ビットターゲットに固有のものではありません。
明確にするために。 strtok
はWindowsではスレッドセーフです。 strtok
はTLS
変数を使用して、各スレッドの最後のポインターを維持します。ただし、strtok
を使用して、スレッドごとに複数のトークン文字列へのアクセスをインターリーブすることはできません。 strtok_r
およびstrtok_s
どちらも、ユーザーが3番目のパラメーターを介してコンテキストを維持できるようにすることで、このインターリーブの問題に対処しています。お役に立てれば。
strtok_rは、POSIXシステム上のstrtokのスレッドセーフバージョンです。
strtok_s は、Windows上のstrtokのバッファオーバーランセーフバージョンです。 Windowsの標準のstrtokはスレッドセーフであるため、strtok_sはそうする必要があります。
MinGWも_WIN32
を事前定義していますが、strtok_r
をサポートしているため、_WIN32
マクロを確認するのは良い考えではないと思います。 Microsoft VisualStudioのマクロである_MSC_VER
マクロを確認することをお勧めします。
#ifdef _MSC_VER
#define strtok_r strtok_s
#endif
警告:Microsoft strtok_s
とC11strtok_s
は完全に異なります! Microsoft strtok_s
には3つのパラメーターしかないのに対し、C11 strtok_s
には4つのパラメーターがあるため、将来的に互換性のある問題になる可能性があります。
Microsoft strtok_s
のプロトタイプは
char* strtok_s(char* str, const char* delimiters, char** context);
C11 strtok_s
のプロトタイプは
char *strtok_s(char *restrict str, rsize_t *restrict strmax, const char *restrict delim, char **restrict ptr);