Loose-Info.com
Last Update 2023/06/22
TOP - 各種テスト - C言語 - 宣言

テスト概要

各種宣言例

記憶域(storage)クラス指定子
extern
static

型指定子

型(type)修飾子
const
restrict

ポインタの宣言
配列の宣言
関数の宣言
型名
typedef
初期化
_Static_assert宣言によるエラーメッセージ出力例


各種宣言例


sample.c
#include <stdio.h> #include <stdlib.h> /* 共用体の定義 */ union uni { unsigned char m1; int m2; }; /* 列挙型の定義 */ enum en { e1 = 8, e2, e3 }; /* 関数の宣言 */ /* 型 + 識別子 + 「(」 */ int main(void) { /* int型オブジェクトの宣言 */ /* 型 + 識別子 */ int i1; /* int型オブジェクトの宣言(初期化子含む) */ int i2 = 2; /* int型オブジェクトの宣言(複数識別子) */ int i3, i4; /* 配列の宣言 */ /* 型 + 識別子 + 「[」 */ int ia[10]; /* ポインタの宣言 */ /* 「*」 + 識別子 */ int *p; /* 構造体の定義・宣言 */ struct st { int mem; } st1; /* 構造体の宣言(初期化子含む) */ struct st st2 = { 6 }; /* 共用体の宣言(初期化子含む) */ union uni uni1 = { 7 }; /* 列挙型の宣言 */ enum en en1; i1 = 1; i3 = 3; i4 = 4; ia[0] = 0; p = ia; st1.mem = 5; en1 = e1; printf("%d %d %d %d %d %d %d %d %d\n", i1, i2, i3, i4, *p, st1.mem, st2.mem, uni1.m2, en1); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample.c $ ./a.out 1 2 3 4 0 5 6 7 8

記憶域(storage)クラス指定子 extern


sample1.c
#include <stdio.h> #include <stdlib.h> /* 関数外でのextern指定子による宣言 */ extern int extern_n1; void func(void) { /* func関数内でのextern指定子による宣言 */ extern int extern_n2; extern_n1++; extern_n2 += 10; printf("func() --- extern_n1 = %d : extern_n2 = %d\n", extern_n1, extern_n2); } int main(void) { /* main関数内でのextern指定子による宣言 */ extern int extern_n2; for (int i=0; i<3; i++) { func(); extern_n2++; printf("extern_n2 = %d\n", extern_n2); } return EXIT_SUCCESS; }
sample2.c
int extern_n1 = 0; int extern_n2 = 10;

実行結果
extern指定子による宣言は、場所を問わずに静的記憶域期間を持つ
$ gcc -Wall sample1.c sample2.c $ ./a.out func() --- extern_n1 = 1 : extern_n2 = 20 extern_n2 = 21 func() --- extern_n1 = 2 : extern_n2 = 31 extern_n2 = 32 func() --- extern_n1 = 3 : extern_n2 = 42 extern_n2 = 43

記憶域(storage)クラス指定子 static


sample1.c
#include <stdio.h> #include <stdlib.h> void call_func(void); void func(void) { printf("sample1.c --- func()\n"); } int main(void) { func(); call_func(); return EXIT_SUCCESS; }
sample2.c
static指定子なしでfunc()を宣言
#include <stdio.h> void func(void) { printf("sample2.c --- func()\n"); } void call_func(void) { func(); }

実行結果
$ gcc -Wall sample1.c sample2.c /usr/bin/ld: /tmp/cc4NOkPy.o: in function `func': func関数の重複宣言に関するエラー発生 sample2.c:(.text+0x0): multiple definition of `func'; /tmp/ccHY4Cb7.o:sample1.c:(.text+0x0): first defined here collect2: error: ld returned 1 exit status

sample2.cのfunc()の宣言を変更
青色部、指定子staticを追加
static void func(void)

実行結果
$ gcc -Wall sample1.c sample2.c <--- func()の宣言が重複しない $ ./a.out sample1.c --- func() sample2.c --- func()

sample3.c
#include <stdio.h> #include <stdlib.h> /* static指定子による宣言 */ static int static_n; void func(void) { static_n += 10; printf("func() --- static_n = %d\n", static_n); } int main(void) { static_n = 0; for (int i=0; i<3; i++) { func(); static_n++; printf("static_n = %d\n", static_n); } return EXIT_SUCCESS; }

実行結果
static指定子による宣言は静的記憶域期間を持つ
$ gcc -Wall sample3.c $ ./a.out func() --- static_n = 10 static_n = 11 func() --- static_n = 21 static_n = 22 func() --- static_n = 32 static_n = 33

型指定子


sample.c
#include <stdio.h> #include <stdlib.h> /* 型指定子 void */ void func(void) {} struct st { int mem; }; union uni { short mem1; int mem2; }; enum weeks {SUN, MON, TUE, WED, THU, FRI, SAT}; typedef int int_sample; int main(void) { /* 各種型指定子 */ char c = 'a'; printf("char c = %c\n", c); short sht1 = -123; printf("short sht1 = %d\n", sht1); unsigned short sht2 = 123; printf("unsigned short sht2 = %d\n", sht2); int i1 = 234; printf("int i1 = %d\n", i1); signed int i2 = -234; printf("signed int i2 = %d\n", i2); long lng = 345; printf("long lng = %ld\n", lng); float f = 4.56; printf("float f = %f\n", f); double d = 5.67; printf("double d = %e\n", d); _Bool b = 1; printf("_Bool b = %d\n", b); struct st st0 = {1}; printf("struct st0.mem = %d\n", st0.mem); union uni un0 = {2}; printf("union uni.mem1 = %d\n", un0.mem1); enum weeks wk = TUE; printf("enum weeks wk = %d\n", wk); int_sample isamp = 678; printf("int_sample isamp = %d\n", isamp); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample.c $ ./a.out char c = a short sht1 = -123 unsigned short sht2 = 123 int i1 = 234 signed int i2 = -234 long lng = 345 float f = 4.560000 double d = 5.670000e+00 _Bool b = 1 struct st0.mem = 1 union uni.mem1 = 2 enum weeks wk = 2 int_sample isamp = 678

型(type)修飾子 const


sample1.c
型修飾子const無し
#include <stdio.h> #include <stdlib.h> int main(void) { int samp_int = 1; printf("%d\n", samp_int); samp_int = 2; printf("%d\n", samp_int); char samp_str1[] = "abc"; printf("%s\n", samp_str1); samp_str1[1] = 'd'; printf("%s\n", samp_str1); char samp_str2[] = "aaa"; char *samp_p1 = samp_str2; samp_p1++; *samp_p1 = 'e'; printf("%s\n", samp_p1); char *samp_p2 = samp_str2; samp_p2++; *samp_p2 = 'e'; printf("%s\n", samp_p2); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample1.c $ ./a.out 1 2 abc adc ea ea

sample2.c
#include <stdio.h> #include <stdlib.h> int main(void) { const int samp_int = 1; printf("%d\n", samp_int); samp_int = 2; printf("%d\n", samp_int); const char samp_str1[] = "abc"; printf("%s\n", samp_str1); samp_str1[1] = 'd'; printf("%s\n", samp_str1); char samp_str2[] = "aaa"; const char *samp_p1 = samp_str2; samp_p1++; *samp_p1 = 'e'; printf("%s\n", samp_p1); char *const samp_p2 = samp_str2; samp_p2++; *samp_p2 = 'e'; printf("%s\n", samp_p2); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample2.c sample2.c: In function ‘main’: sample2.c:9:18: error: assignment of read-only variable ‘samp_int’ 9 | samp_int = 2; <--- 変数 samp_int はconstにより変更不可 | ^ sample2.c:15:22: error: assignment of read-only location ‘samp_str1[1]’ 15 | samp_str1[1] = 'd'; <--- 変数 samp_str1 はconstにより変更不可 | ^ sample2.c:22:18: error: assignment of read-only location ‘*samp_p1’ 22 | *samp_p1 = 'e'; <--- ポインタ samp_p1 が指すオブジェクトはconstにより変更不可 | ^ sample2.c:26:16: error: increment of read-only variable ‘samp_p2’ 26 | samp_p2++; <--- ポインタ samp_p2 そのものはconstにより変更不可 | ^~

型(type)修飾子 restrict


sample1.c
#include <stdio.h> #include <stdlib.h> void func(char *p1, char *p2) { *p1 = *(++p2); } int main(void) { char s[] = "abc"; func(s, s); printf("%s\n", s); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample1.c $ ./a.out bbc

sample1.cの関数の宣言を変更してsample2.cとしてコンパイルを実行
青色部、型修飾子restrictを追加
void func(char *restrict p1, char *p2)

実行結果
$ gcc -Wall sample2.c sample2.c: In function ‘main’: sample2.c:13:14: warning: passing argument 1 to ‘restrict’-qualified parameter aliases with argument 2 [-Wrestrict] 13 | func(s, s); <--- 引数1がrestrict修飾子を持つため、引数2が同じオブジェクトへのポインタとなることで警告が発生 | ^ ~

ポインタの宣言


sample.c
#include <stdio.h> #include <stdlib.h> int main(void) { int i1 = 1; int i2 = 2; /* int型ポインタを宣言 */ int *ip1; ip1 = &i1; /* int型ポインタを宣言・初期化 */ int *ip2 = &i2; /* int型ポインタの宣言・NULLポインタとしての定義 */ int *ip3 = NULL; printf("%d %d %p\n", *ip1, *ip2, ip3); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample.c $ ./a.out 1 2 (nil)

配列の宣言


sample.c
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { /* 固定長配列の宣言 */ int i1[3]; i1[0] = 1; printf("i1[0] = %d\n", i1[0]); if ((argc > 1) && (atoi(argv[1]))) { /* 可変長配列の宣言 */ int i2[atoi(argv[1])]; for (int i=0; i<atoi(argv[1]); i++) { i2[i] = i * 10; } printf("argv[1] = %s --- i2[%d] = %d\n", argv[1], atoi(argv[1]) - 1, i2[atoi(argv[1]) - 1]); } else { /* 初期化リストを伴う配列長を省略した宣言 */ int i2[] = { -1 }; printf("i2[0] = %d\n", i2[0]); } return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample.c $ ./a.out i1[0] = 1 i2[0] = -1 $ ./a.out 5 i1[0] = 1 argv[1] = 5 --- i2[4] = 40

関数の宣言


sample.c
#include <stdio.h> #include <stdlib.h> /* 引数が無く引数宣言が空 */ void func1(); /* 引数は有るが引数宣言が空 */ void func2(); /* 引数が無く型voidによる引数宣言 */ void func3(void); /* コンマ区切りによる引数宣言 */ void func4(int n1, int n2); /* 識別子を省略したコンマ区切りによる引数宣言 */ void func5(int, int); int main(int argc, char *argv[]) { func1(); func2(1); func3(); func4(2, 3); func5(4, 5); return EXIT_SUCCESS; } void func1() { printf("func1()\n"); } void func2(int n) { printf("func2() %d\n", n); } void func3(void) { printf("func3()\n"); } void func4(int n1, int n2) { printf("func4() %d %d\n", n1, n2); } void func5(int n1, int n2) { printf("func5() %d %d\n", n1, n2); }

実行結果
$ gcc -Wall sample.c $ ./a.out func1() func2() 1 func3() func4() 2 3 func5() 4 5

型名


sample.c
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { printf("型名使用例\n\n"); /* 型char */ printf("sizeof(char) = %ld\n", sizeof(char)); /* 型int */ printf("sizeof(int) = %ld\n", sizeof(int)); /* 型long */ printf("sizeof(long) = %ld\n\n", sizeof(long)); /* charへのポインタ */ printf("sizeof(char *) = %ld\n", sizeof(char *)); /* intへのポインタ */ printf("sizeof(int *) = %ld\n", sizeof(int *)); /* longへのポインタ */ printf("sizeof(long *) = %ld\n\n", sizeof(long *)); /* charへのポインタの配列(要素数5) */ printf("sizeof(char *[5]) = %ld\n", sizeof(char *[5])); /* charの配列(要素数5)へのポインタ */ printf("sizeof(char (*)[5]) = %ld\n", sizeof(char (*)[5])); /* unsigned intを返す引数無しの関数へのポインタ */ printf("sizeof(unsigned int (*)(void)) = %ld\n", sizeof(unsigned int (*)(void))); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample.c $ ./a.out 型名使用例 sizeof(char) = 1 sizeof(int) = 4 sizeof(long) = 8 sizeof(char *) = 8 sizeof(int *) = 8 sizeof(long *) = 8 sizeof(char *[5]) = 40 sizeof(char (*)[5]) = 8 sizeof(unsigned int (*)(void)) = 8

typedef


sample.c
#include <stdio.h> #include <stdlib.h> /* typedef名td_intをintの同義語として定義 */ typedef int td_int; /* typedef名td_structを構造体sample_structの同義語として定義 */ typedef struct sample_struct { int i; float f; } td_struct; void func0(int , const char *); void func1(int , const char *); /* typedef名td_funcを戻り値の無い 引数(int, const char*)を伴う関数へのポインタの同義語として定義 */ typedef void (*td_func)(int, const char*); /* 引数にtypedef名td_funcを使用する関数のプロトタイプ宣言 */ void func10(int , td_func); int main(void) { td_int sample1 = 1; td_struct sample2 = {2, 3.3}; printf("sample1 = %d\n", sample1); printf("sample2 = {%d, %f}\n", sample2.i, sample2.f); func10(10, func0); func10(10, func1); return EXIT_SUCCESS; } void func0(int i, const char *s) { printf("func0(%d, \"%s\"))\n", i * 10, s); } void func1(int i, const char *s) { printf("func1(%d, \"%s\"))\n", i * 100, s); } void func10(int i, td_func func) { printf("func10(%d, ", i); (*func)(i, "abc"); }

実行結果
$ gcc -Wall sample.c $ ./a.out sample1 = 1 sample2 = {2, 3.300000} func10(10, func0(100, "abc")) func10(10, func1(1000, "abc"))

初期化


sample.c
#include <stdio.h> #include <stdlib.h> struct samp_struct { int i; float f; }; void func(void) { printf("func()\n"); } int main(int argc, char *argv[]) { /* スカラ型オブジェクトの初期化 */ int i1 = 1; int i2 = 2, i3 = 3; int *p1 = &i1; /* 関数ポインタの初期化 */ void (*samp_func)(void) = func; /* 配列型を初期化子リストで初期化 */ int i4[3] = {4, 5, 6}; /* 構造体を初期化子リストで初期化 */ struct samp_struct st1 = {7, 8.8}; printf("%d %d %d %d\n", i1, i2, i3, *p1); (*samp_func)(); for (int i=0; i<3; i++) {printf("%d ", i4[i]);} printf("%d %f\n", st1.i, st1.f); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample.c $ ./a.out 1 2 3 1 func() 4 5 6 7 8.800000

_Static_assert宣言によるエラーメッセージ出力例


sample.c
#include <stdio.h> #include <stdlib.h> int main(void) { /* _Static_assert宣言によるエラーメッセージ出力例 */ _Static_assert(sizeof(int) == 2, "sizeof(int) != 2"); printf("main()\n"); return EXIT_SUCCESS; }

実行結果
$ gcc -Wall sample.c sample.c: In function ‘main’: sample.c:8:9: error: static assertion failed: "sizeof(int) != 2" 8 | _Static_assert(sizeof(int) == 2, "sizeof(int) != 2"); | ^~~~~~~~~~~~~~

実行環境

GNU bash, version 5.1.16
GCC-12.2.0
GNU C Library 2.36
GNU Binutils 2.39


コード例・出力内容中の表記

・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。