TENKAIKEN Storehouse

Contents ♪

C言語~C99で追加された仕様 2024.06.17
行末までコメント(C++のコメントを採用
C++と同様、「//」から行末までをコメントとする。
#include <stdio.h>

int main()
{
    printf("hello World\n");    // 行末までコメント
}
C99以前から多くのコンパイラ環境で独自に採用されていたが、公式に取り込まれた。
C言語~C99で追加された仕様 2024.06.11
変数宣言はブロック先頭でなくてもよい
変数宣言の位置はC90までは関数定義などのブロックの先頭にまとめる必要があったが、C99からはC++と同様に、参照前なら先頭でなくてもよくなった。
#include <stdio.h>

int main()
{
    printf("hello\n");
    int a = 10;         // 変数宣言が先頭ではない
    printf("hello %d\n", a);
}
上は、C90ではエラーになる。
ただしgccでコンパイルする場合は、-std=c90を指定してもgcc拡張が適用されてエラーにならない。
gccで厳密なC90を試すならば、-pedantic-errorsをつけてコンパイルするとよい。
C言語~C99で追加された仕様 2024.06.14
forの初期化部で変数宣言ができる
C++のように、for文の初期化部で変数宣言ができる。
#include <stdio.h>
#
int main()
{
    for (int i = 0; i < 5; i++) {
        printf("%d\n", i);
    }
}
C言語~C99で追加された仕様 2024.06.11
bool型
真理値(ブール)型の導入。
型名は「bool」または「_Bool」、リテラルは「true」「false」。stdbool.hのインクルードが必要。
#include <stdio.h>
#include <stdbool.h>

int main()
{
    // C99 bool型、true/falseが追加
    // _Bool または bool
    //bool f = false;
    _Bool f = true;
    printf("hello %d\n", f);
}
上の結果は「hello 1」と出る。つまりtrue=1である。
上の_Boolはboolでもよい。
C言語~C99で追加された仕様 2024.06.14
64ビット整数
long long(long long int) 64bit整数の導入。
#include <stdio.h>

int main()
{
    long long lx = 1000LL;
    unsigned long long ulx = 2000ULL;
    long long int lxi = 3000LL;
    printf("hallo %lld %llu %lld\n", lx, ulx, lxi);
}
64bitのLinuxはlongもlong longも同じ64ビット整数である。Windowsは64ビットでも従来どおりにlongは32ビットで、long longは64ビットである。定数のサフィックスはlongがLで、long longはLL、printfのフォーマットも%lldのように。
C言語~C99で追加された仕様 2024.06.14
ビット数が明確な整数型
プラットフォームに依存しないビット数が明確な整数型の定義。
#include <stdio.h>
#include <stdint.h>
//#include <inttypes.h>

int main()
{
    int8_t i8 = INT8_MIN;
    int16_t i16 = INT16_MAX;
    int32_t i32 = INT32_MIN;
    int64_t i64 = INT64_MAX;

    uint16_t ui16 = UINT16_MAX;
    uint64_t ui64 = UINT64_MAX;

    printf("int8  %d\n", i8);       // int8  -128
    printf("int16 %d\n", i16);      // int16 32767
    printf("int32 %d\n", i32);      // int32 -2147483648
    printf("int64 %ld\n", i64);     // int64 9223372036854775807
    printf("uint16 %u\n", ui16);    // uint16 65535
    printf("uint64 %lu\n", ui64);   // uint64 18446744073709551615
}
stdint.hかinttypes.hのインクルードが必要。inttypes.hはstdint.hに加えてprintfの書式に便利なマクロが定義されている。
stdint.hには、次のような各整数型の最小・最大値がマクロ定義されている。
                                                                               
Type 最小値 最大値
int8_t INT8_MIN INT8_MAX
int16_t INT16_MIN INT16_MAX
int32_t INT32_MIN INT32_MAX
int64_t INT64_MIN INT64_MAX
uint8_t - UINT8_MAX
uint16_t - UINT16_MAX
uint32_t - UINT32_MAX
uint64_t - UINT64_MAX
size_t - SIZE_MAX
C言語~C99で追加された仕様 2024.06.14
指定する添字の排列要素を初期化する(指示初期化子)
配列の添字を個別に指定して初期化できる。
int arr[] = { [添字] = 初期値, [添字] = 初期値, ... };
#include <stdio.h>
#
int main()
{
    int arr[] = { 10, [3] = 13, 14 };
            // C99 指示初期化子 配列の添字を指定して初期化できる。
            // 指示初期化の添字前は、数値なら0、ポインタはNULLで初期化される。
    int i;
    for (i = 0; i < 5; i++) {
        printf("%d\n", arr[i]);
    }
}
10
0
0
13
14
指示初期化子の後の通常の初期値は、その次の添字から始まる。初期値が指定されない範囲は0クリア(浮動小数点なら0.0でポインタはNULL)になる。
C言語~C99で追加された仕様 2024.06.14
指定する構造体メンバを初期化する(指示初期化子)
構造体のメンバを個別に指定して初期化できる。
struct 構造体 x = { .メンバ名 = 初期値, .メンバ名 = 初期値, ... };
#include <stdio.h>

int main()
{
    struct Person {
        int age;
        char *name;
    } psn = { .age = 49, .name = "yamane" };
    // すべてのメンバを初期化しなくてもよい

    printf("%d %s\n", psn.age, psn.name);
}
初期値が指定されないメンバは0クリア(浮動小数点なら0.0でポインタはNULL)になる。
C言語~C99で追加された仕様 2024.06.14
動的なサイズ指定による配列宣言
スタックに確保する自動変数の配列は、サイズを変数や演算の結果により動的に指定できる。※
#include <stdio.h>
#include <string.h>
#
int main()
{
    int sz = 10;
    char s[sz];         // 変数szの値で配列サイズが決まる
    strcpy(s, "Hello");
    printf("%s\n", s);
}
静的配列には動的サイズは指定できない
C言語~C99で追加された仕様 2024.06.14
サイズ0の配列宣言
サイズ0の配列が宣言できる。
主に構造体のメンバとして、サイズが不明な配列として定義する場合に有効である。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    struct Person {
        int size;
        char name[];        // C99 サイズ0の配列
                            // C90までは1以上のサイズでないと配列は宣言できなかった。
                            // バッファサイズ未定で動的に確保する場合などでサイズ0の配列を定義できる
                            // C90ではエラーになることを確認した。
    };

    struct Person *p = malloc(sizeof(struct Person) + 10);;
    strcpy(p->name, "Yamane");
    printf("%s\n", p->name);
}
上のような動的にサイズが決まる配列メンバのnameは、C90ではname[1]のようにする必要があった。
C言語~C99で追加された仕様 2024.06.14
複合リテラル
 配列・構造体のリテラル(定数)を表現できる(複合リテラル)。
構造体のリテラル    (構造体){値, 値, ..}
配列のリテラル      (型 []){値, 値, ..}
#include <stdio.h>

struct Person {
    int age;
    char name[10];
};

void PrintPerson(struct Person *p)
{
    printf("%s %d\n", p->name, p->age);
}

struct Person GetPerson()
{
    return (struct Person){50, "Tanaka"};
}

int main()
{
    PrintPerson(&(struct Person){49, "Yamane"});    // 構造体のリテラル

    struct Person p = GetPerson();
    printf("%s %d\n", p.name, p.age);

    for (int i = 0; i < 5; i++) {
        printf("%d\n", (int []){10, 20, 30, 40, 50}[i]);    // 配列のリテラル
    }
}
Yamane 49
10
20
30
40
50
C90までは、配列は文字列のみ定数を表現できていたが、それ以外の構造物のリテラルの表現方法はなかった。複合リテラルにより、構造体や配列の変数を確保してから初期化しなくても、リテラルとして表現できるようになった。
C言語~C99で追加された仕様 2024.06.17
インライン関数
inline指示子により、関数をインライン化できる。
#include <stdio.h>
#include "test12.h"

// C99 inline関数

static inline int add(int a, int b)
{
    return a + b;
}

int main()
{
    printf("%d\n", add(10, 5));
}
gccではstaticまたはexternのスコープを明示的に指定する必要がある。リンカがインライン関数の実体が見つけられないというエラーにされる。
C言語~C99で追加された仕様 2024.06.17
可変長引数マクロ関数
可変長な引数を受け取るマクロ関数の定義が可能。
#define 関数(...)    func(__VA_ARGS__)  
マクロ関数の可変長引数の部分を「...」として、__VA_ARGS__に展開する。
#include <stdio.h>

#define PR(fmt, ...)    printf(fmt, __VA_ARGS__)

int main()
{
    PR("Hello %d %d\n", 10, 20);        // Hello 10 20 
}
C言語~C99で追加された仕様 2024.06.14
現在の関数を参照するマクロ
デバッグに便利な「現在の関数名」が参照できるマクロが定義された。
__func__    現在の関数名
__LINE__    現在の行番号
__FILE__    現在のソースファイル名
#include <stdio.h>

void theFunction()
{
    printf("%s %d %s\n", __func__, __LINE__, __FILE__);
}

int main()
{
    theFunction();
}
theFunction 5 test08.c
__LINE__と__FILE__はC90から存在する。