strncpy, strncpy_s
ja.cppreference.net より
| ヘッダ <string.h>
|
||
char* strncpy( char* dest, const char* src, size_t count );
|
(1) | (C99 まで) |
char* strncpy( char* restrict dest, const char* restrict src, size_t count );
|
(C99 以降) | |
errno_t strncpy_s( char* restrict dest, rsize_t destsz,
const char* restrict src, rsize_t count );
|
(2) | (C11 以降) |
1)
count によって指される文字配列の最大 src 文字を(終端ナル文字を含むが、ナル文字に続く文字は含まない) dest によって指される文字配列にコピーする。 もし
count に達する前に配列全体 src がコピーされた場合、結果の文字配列はナル終端されない。 もし
src から終端ナル文字をコピーした後、 count に達しない場合、合計 dest 文字が書き込まれるまで追加のナル文字が count に書き込まれる。 文字配列が重なる場合、
dest または src のいずれかが文字配列へのポインタでない場合( dest または src がヌルポインタの場合を含む)、 dest によって指される配列のサイズが count 未満である場合、または src によって指される配列のサイズが count 未満でナル文字を含まない場合、動作は未定義である。2) (1) と同じですが、異なる点は、関数が宛先配列にゼロを書き込んで
count まで埋め続けないこと、終端ナル文字を書き込んだ後に停止することです(ソースにナルがない場合は、 dest[count] にナルを書き込んで停止します)。また、以下のエラーが実行時に検出され、現在インストールされている 制約ハンドラ 関数を呼び出します:
srcまたはdestがヌルポインタであるdestszがゼロまたは RSIZE_MAXcountより大きいRSIZE_MAXcountより大きいdestsz以上であるが、destszがstrnlen_s(src, count)以下である、つまり切り詰めが発生する- ソース文字列と宛先文字列の間で重なりが発生する
dest < strnlen_s(src, destsz) < によって指される文字配列のサイズが destsz 未満である場合の動作は未定義です。言い換えれば、誤った destsz の値は差し迫ったバッファオーバーフローを露呈しません。 src < strnlen_s(src, count) < destsz によって指される文字配列のサイズが count 未満である場合の動作は未定義です。言い換えれば、誤った の値は差し迫ったバッファオーバーフローを露呈しません。
strncpy_s すべての境界チェック関数と同様に、 __STDC_LIB_EXT1__ は、実装によって __STDC_WANT_LIB_EXT1__ が定義され、ユーザーが 1 を整数定数 < として定義し、 >string.h関連項目
| dest | - | コピー先の文字配列へのポインタ |
| src | - | コピー元の文字配列へのポインタ |
| count | - | コピーする最大文字数 |
| destsz | - | 宛先バッファのサイズ |
戻り値
1)
destのコピーを返す2)
dest[0] 成功時にはゼロを返し、エラー時には非ゼロを返す。また、エラー時には dest にゼロを書き込む( destsz がヌルポインタであるか、 RSIZE_MAX がゼロまたはそれより大きい場合を除く)。また、宛先配列の残りを未指定の値で上書きする可能性がある。ノート
C11 後の DR 468 で修正されたように、 strncpy_s は、 strcpy とは異なり、エラーが発生した場合にのみ宛先配列の残りを上書きすることが許可されている。
strncpy とは異なり、 strncpy_s は宛先配列をゼロで埋めない。これは、既存のコードを境界チェック版に変換する際の一般的なエラーの原因である。
宛先バッファに合わせた切り詰めはセキュリティリスクであるため、 strncpy_s のランタイム制約違反となるが、 count を宛先配列のサイズから 1 を引いた値に指定することで切り詰め動作を実現できる。最初の count バイトをコピーし、通常通りナル終端子を追加する: strncpy_s(dst, sizeof dst, src, (sizeof dst)-1);
例
このコードを実行する
#define __STDC_WANT_LIB_EXT1__ 1
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char src[] = "hi";
char dest[6] = "abcdef"; // no null terminator
strncpy(dest, src, 5); // writes five characters 'h', 'i', '\0', '\0', '\0' to dest
printf("strncpy(dest, src, 5) to a 6-byte dest gives : ");
for (size_t n = 0; n < sizeof dest; ++n) {
char c = dest[n];
c ? printf("'%c' ", c) : printf("'\\0' ");
}
printf("\nstrncpy(dest2, src, 2) to a 2-byte dst gives : ");
char dest2[2];
strncpy(dest2, src, 2); // truncation: writes two characters 'h', 'i', to dest2
for (size_t n = 0; n < sizeof dest2; ++n) {
char c = dest2[n];
c ? printf("'%c' ", c) : printf("'\\0' ");
}
printf("\n");
#ifdef __STDC_LIB_EXT1__
set_constraint_handler_s(ignore_handler_s);
char dst1[6], src1[100] = "hello";
errno_t r1 = strncpy_s(dst1, 6, src1, 100); // writes 0 to r1, 6 characters to dst1
printf("dst1 = \"%s\", r1 = %d\n", dst1,r1); // 'h','e','l','l','o','\0' to dst1
char dst2[5], src2[7] = {'g','o','o','d','b','y','e'};
errno_t r2 = strncpy_s(dst2, 5, src2, 7); // copy overflows the destination array
printf("dst2 = \"%s\", r2 = %d\n", dst2,r2); // writes nonzero to r2,'\0' to dst2[0]
char dst3[5];
errno_t r3 = strncpy_s(dst3, 5, src2, 4); // writes 0 to r3, 5 characters to dst3
printf("dst3 = \"%s\", r3 = %d\n", dst3,r3); // 'g', 'o', 'o', 'd', '\0' to dst3
#endif
}
出力例:
strncpy(dest, src, 5) to a 6-byte dst gives : 'h' 'i' '\0' '\0' '\0' 'f'
strncpy(dest2, src, 2) to a 2-byte dst gives : 'h' 'i'
dst1 = "hello", r1 = 0
dst2 = "", r2 = 22
dst3 = "good", r3 = 0
参考文献
- C23 規格 (ISO/IEC 9899:2024):
- 7.24.2.4 The strncpy function (p: TBD)
- K.3.7.1.4 The strncpy_s function (p: TBD)
- C17 規格 (ISO/IEC 9899:2018):
- 7.24.2.4 The strncpy function (p: 265)
- K.3.7.1.4 The strncpy_s function (p: 447-448)
- C11 規格 (ISO/IEC 9899:2011):
- 7.24.2.4 The strncpy function (p: 363-364)
- K.3.7.1.4 The strncpy_s function (p: 616-617)
- C99 規格 (ISO/IEC 9899:1999):
- 7.21.2.4 The strncpy function (p: 326-327)
- C89/C90 規格 (ISO/IEC 9899:1990):
- 4.11.2.4 The strncpy function
関連項目
(C11) |
一方の文字列を他方にコピーする (関数) |
(C11) |
一方のバッファを他方にコピーする (関数) |
(動的メモリ TR) |
指定されたサイズまでの文字列のコピーを割り当てる (関数) |
C++ ドキュメント for strncpy
| |