Last Update 2023/06/22
テスト概要
記憶域(storage)クラス指定子
型(type)修飾子
各種宣言例
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指定子による宣言は、場所を問わずに静的記憶域期間を持つ
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()を宣言
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を追加
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指定子による宣言は静的記憶域期間を持つ
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無し
型修飾子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を追加
青色部、型修飾子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
GCC-12.2.0
GNU C Library 2.36
GNU Binutils 2.39
コード例・出力内容中の表記
・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。