文字列リテラル中のナル文字

C言語勉強会にて、char の配列の途中に\0をセットすると文字列としてはそこで終端されると説明した。ある人が次のようなコードを試した。

char str[] = "0123456\0789"; /* 元々は"0123456789" */
printf("%s\n", str);

コンソールに
0123456
と表示されると思っていたのだが表示されたのは
012345689
だった。7はどこへ?


文字定数として\oooは8進数を表すただしoooは2桁もしくは3桁の8進数である。パーサは解釈できる最長のものをトークンとするので\07までを一つの文字定数として解釈する。078は8進数としては解釈できない。

以下検証用のコード

#include <stdio.h>

int main(void)
{
    /* 下記は次の宣言と同等の意味。簡単にかけるようになっている
    str1の宣言は次と同等(コンパイラは下記のように解釈している)
    char str1[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0'};
    */
    char str1[] = "0123456789";
    /* str2の場合は以下と同等 
    char str2[] = {'0', '1', '2', '3', '4', '5', '6', '\07', '8', '9', '\0'};
    */
    char str2[] = "0123456\0789";
    
    int i;

    printf("----- str1の場合 ---------\n");
    printf("%s sizeof(str1): %d\n", str1, sizeof(str1));
    for (i = 0; i < sizeof(str1); i++) {
        printf("%d文字目 %c コード %#x\n", i, str1[i], str1[i]);
    }

    printf("----- str2の場合 ---------\n");
    printf("%s sizeof(str2): %d\n", str2, sizeof(str2));
    for (i = 0; i < sizeof(str2); i++) {
        printf("%d文字目 %c コード %#x\n", i, str2[i], str2[i]);
    }
    
    return 0;
}