web-dev-qa-db-ja.com

Cのstrtok_rとstrtok_sの違いは何ですか?

LinuxとWindowsでコンパイルできる必要があるCプログラムでこの関数を使用しようとしています。最初はstrtok_rを使用しようとしましたが、Windowsでコンパイルすると、関数が存在しないと文句を言い、extern関数であると想定すると表示されましたが、失敗しました。次に、strtok_sを使用してコンパイルしました!次にLinuxを試してみましたが、「strtok_s 'への未定義の参照」があると文句を言っています。

1つはWindows専用の機能で、もう1つはLinuxの機能ですか?両方でコンパイルするにはどうすればよいですか?

22
petranaya

これらの関数はどちらも、文字列を解析するための非常に醜く直感的でないイディオムであり、通常、特定のアプリケーションの要件を微妙に満たすことができません。標準Cの単純なstrtokの場合はさらにそうです。それらを破棄して独自のコードを記述し、char配列を反復処理して、必要に応じて分割します。 strchrstrspn、および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のみを使用できるようになりました。

35

他の回答についてコメントするのに十分な評判がないので、自分で回答する必要があります。

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ビットターゲットに固有のものではありません。

10
BeReal82

明確にするために。 strtokはWindowsではスレッドセーフです。 strtokTLS変数を使用して、各スレッドの最後のポインターを維持します。ただし、strtokを使用して、スレッドごとに複数のトークン文字列へのアクセスをインターリーブすることはできません。 strtok_rおよびstrtok_sどちらも、ユーザーが3番目のパラメーターを介してコンテキストを維持できるようにすることで、このインターリーブの問題に対処しています。お役に立てれば。

5
Jamey Kirby

strtok_rは、POSIXシステム上のstrtokのスレッドセーフバージョンです。

strtok_s は、Windows上のstrtokのバッファオーバーランセーフバージョンです。 Windowsの標準のstrtokはスレッドセーフであるため、strtok_sはそうする必要があります。

4
Martin Beckett

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);
0
Victor