【C言語】文字配列に終端文字¥0を入れる隙間が無い時はstrNcpyよりC99構造体の指示初期化子が便利

指示付きの初期化子

warning: ‘strncpy’ output truncated before terminating nul copying 8 bytes from a string of the same length

警告:「strncpy」出力は、
第三引数と同じ長さの文字列から
8バイトをコピーして
終端文字\0を出力する前に切り捨てられました
[-Wstringop-truncation]

■strcpy(dsname)で警告が出る例

#include    <string.h>
#include    <stdio.h>
typedef unsigned char   UB ;
struct  ctsk {
    int foo,bar,baz ;
    UB dsname[8];
} ;
void    cre_tsk(struct ctsk *p){
    printf("dsname=%.8s\n",p->dsname);
}
int main(void){
    struct  ctsk     x ;
    x.foo = 1; 
    x.bar = 2;
    x.baz = 3;
    strncpy(x.dsname,"12345678",8) ;
    cre_tsk(&x);
}

UB dsname[8]の設定でピッタリ8文字設定したいとき、
strncpy()を使用すると終端文字\0が出力に設定されないと
gcc -Wall で警告されます。

■C89構造体初期化を使った修正例

#include    <string.h>
#include    <stdio.h>
typedef unsigned char   UB ;
struct  ctsk {
    int foo,bar,baz ;
    UB dsname[8];
} ;
void    cre_tsk(struct ctsk *p){
    printf("dsname=%.8s\n",p->dsname);
}
int main(void){
    struct  ctsk     x ={
        1, 
        2,
        3,
        "12345678"
    } ;
    cre_tsk(&x);
}

C89仕様の古いC言語では上記のように
構造体の宣言と同時に初期化すると
strncpy()を使用する必要がないので警告は消えますが
どのメンバを初期化しているのかわかりにくいといった欠点があります。

■C99指示初期化子を使った修正例

#include    <string.h>
#include    <stdio.h>
typedef unsigned char   UB ;
struct  ctsk {
    int foo,bar,baz ;
    UB dsname[8];
} ;
void    cre_tsk(struct ctsk *p){
    printf("dsname=%.8s\n",p->dsname);
}
int main(void){
    struct  ctsk     x ={
        .foo=1, 
        .bar=2,
        .baz=3,
        .dsname="12345678"
    } ;
    cre_tsk(&x);
}

C99仕様のC言語では上記のように構造体の宣言時に指示初期化子が使えます。

strncpy()を使用する必要がないので警告は消え、
どのメンバを初期化しているのか明確にわかります。

■注意事項

dsname に終端文字\0 が無い場合はdsnameは文字列ではないので
strlen(x.dsname)とか
strcpy(dst,x.dsname)とか
文字列操作関数を使用すると終端文字\0を見つけられずに
暴走する可能性があります。

参考:

プログラミング言語 C の新機能

http://seclan.dll.jp/c99d/