Linux Windows 初心者向け

【初心者向け】C言語の基本的な文法(前編)

C言語の基本的な文法をざっくり紹介します。

極力さらっと読める感じにしていますが、たまにマニアックな話題(中・上級者向けのネタ)に触れています。

前編ではカンタンなプログラム実行方法(HelloWorld)①プリプロセッサ指令、②変数、③定数(リテラル)、④分岐処理、⑤反復(ループ)処理、⑥演算子を説明します。

環境

Windows10 Home(64bit)1903

VMware Player 15上で動くUbuntu18.04

この記事で解決できること

  • C言語の基本的な文法を知ることが出来る。

関連記事

【初心者向け】C言語の基本的な文法(前編)

【初心者向け】C言語の基本的な文法(中編)

【初心者向け】C言語の基本的な文法(後編)

 

C言語開発環境をつくる方法

①Linuxで開発する

≫【Ubuntu18.04】プログラミング環境を無料で構築する方法

 

②Windowsで開発する

≫【MinGW】無料のC/C++プログラミング環境をインストールしよう

 

今回のサンプルはLinux、Windowsどちらでも実行できるように記載しています。

以降、コンパイル&プログラム実行はLinuxを前提に記載していますが、

Windowsで実行する場合、gcc構文は同じでOK。プログラム実行時は「./test」を「test.exe」に読み替えてください。

超カンタンなプログラムの書き方(HelloWorld)

テキストエディタを開き「test.c」というファイルを作成。

以下の内容をコピペして保存。

コンパイル&プログラム実行。HelloWorldと表示されます。

 command
$ gcc -g -o test test.c
$ ./test
Hello World

 

解説します。よく分からない用語が出てきたら是非自分で調べてみてください。

 

1~3行目:コメント。/**/で囲うことで複数行に渡るコメントを書けます。//で行コメントにすることもできます。

≫参考: C言語入門:コメントの書き方(Geekなページ)

 

4行目:インクルード宣言。標準入出力に関する関数を定義したstdio.hというヘッダーファイルを読み込みます。stdio.hを読み込むことで7行目のprintf関数を呼ぶことができます。stdioはSTandarDInputOutputの略語です。

≫参考:#include <stdio.h>はおまじないじゃないぞ。

 

5行目:メイン関数。C言語のプログラムはmain関数から実行開始するルールになっています。argc(argument counter)に引数の個数、argv(argument vector)に引数の配列が格納されます。

※main関数を実行する前にアセンブラのプログラムが実行されスタックメモリの初期化などC言語のプログラムを実行するための準備をしますが今回は説明しません。

≫参考:argc,argvとは?(Qiita)

 

6行目:ブロック開始。

≫参考:ブロック_(プログラミング)(Wikipedia)

 

7行目:printf関数。”HelloWorld\n”という文字列を標準出力(stdout)に表示します。\nは改行コードです。

≫参考:C言語関数辞典:printf

 

8行目:リターン文。プログラムの終了コード(今回は0)を返却します。

≫参考:C言語入門:関数(2):return文(Geekなページ)

 

9行目:ブロック終了。

 

ちょっと面倒に思われるかもしれませんが慣れないうちは上記のように「インクルード宣言とは?」「main関数とは?」「printfとは?」「returnとは?」と1行ずつ意味を調べてコツコツとC言語の語彙を増やしていくことをオススメします。ちょっと調べたいときはインターネットで検索できますし、体系的に学びたいときはC言語の本を読めばOKです。

 

①プリプロセッサ指令、②変数、③定数(リテラル)、④分岐処理、⑤反復(ループ)処理、⑥演算子

①プリプロセッサ指令(ディレクティブ)

コンパイルの前処理を指示します。

構文

意味

#include <標準ヘッダファイル.h>

例:#include <stdio.h>

#include "自作ヘッダファイル.h"

例:#include "my_function.h"

ファイルの読み込み

#define 定数名    定数

例:#define AUTHER_NAME    ( "pavement1234" )

例:#define MAX_VALUE    ( 12345 )

#define マクロ名( 引数, ... )    処理

例:#define ADD( a, b )    ( a + b )

定義済マクロ

__FILE__ ファイル名

__LINE__ 行番号

__DATE__ コンパイル日付

__TIME__ コンパイル時間

__STDC__ ANSI規格対応なら1、非対応なら0

定数、マクロ定義

#error ”エラーメッセージ”

例:#error "Prosessor name is unknown."

コンパイル時にエラーを発生させます。

条件コンパイル(#ifディレクティブなど)と組合わせて利用するのが普通です。例えばプロセッサ名が未知のためヘッダファイルが特定できないなど、コンパイル継続が難しいときにエラーを発生させたりします。

#warning "警告メッセージ”

例:#warning "Function AAA is not recommended"

 

コンパイル時にワーニングを発生させます。

条件コンパイル(#ifディレクティブなど)と組合わせて利用するのが普通です。例えば推奨されない関数を利用する場合など、コンパイル時に警告メッセージを出したりします。

#if    条件1

    条件1のときにコンパイルする処理

#elif    条件2

    条件2のときにコンパイルする処理

#else

    条件1、2に該当しない場合にコンパイルする処理

#endif

条件コンパイル

#if defined(マクロ名) で#ifdefと同じ効果が得られます。

#if !defined(マクロ名) で#ifndefと同じ効果が得られます。

#ifdef ( #ifndef ) 定数またはマクロ

 マクロに一致(不一致)したときにコンパイルする処理

#else

 マクロに一致しない(一致する)ときにコンパイルする処理

#endif

条件コンパイル

#pragma  プロセッサやOS依存の命令

例:#pragma once //同じヘッダファイルを読み込ませない

例:#pragma comment( lib, ".lib") //リンクするライブラリを指定

プロセッサやOS依存の命令。

※VC++で多用されています。

 

#

例:#define TO_STRING( str )    #str

TO_STRING( abcde ) //マクロ展開結果は"abcde"という文字列になる。変数名などを文字列に変換できる。

マクロ実引数を文字列化する。

##

例:#define MERGE_STRING( a, b )    a ## b

MERGE_STRING( "param", "1" ) // マクロ展開結果は"param1"という文字列になる。

前後の字句列を結合する。

 

2重インクルード防止

たとえば、my_func.hという自作ヘッダファイルを作ったときに、複数のCソースからmy_func.hをインクルードされても2回以上読み込ませないようにするための仕組みです。

my_func.hはmy_func.c、AAA.c、BBB.cの3つのCソースからインクルードされていますが、1回目で__MY_FUNC__というマクロが定義されるため2回目以降は#ifndef __MY_FUNC_H__の条件に合致しないためヘッダファイルの内容は読み込まれません。

my_func.h

my_func.c

AAA.c

BBB.c

 

アライメント調整テクニック

構造体(中編に出てきます)のアライメントを調整するときに#pragmaを使うことがあります。

 

②変数

変数とは値を保存するメモリ領域です。保存する値によって型が変わります。

以下の例ではintという整数型のaという変数を定義し、aに12345という値を代入します。

 

32bitプロセッサの例です。

型名 意味 値の範囲

char

符号あり文字型(8bit) -128~+127

unsigned char

符号なし文字型(8bit) 0~+255

short

符号あり短整数型(16bit) -32768~+32767

unsigned short

符号あり短整数型(16bit) 0~+65535

int

符号あり整数型(32bit)

処理系依存

32bitプロセッサの場合longと同じと考えてよい。

unsigned int

符号あり整数型(32bit)

処理系依存

32bitプロセッサの場合unsigned longと同じと考えてよい。

long

符号あり長整数型(32bit) -2147483648~+2147483647

unsigned long

符号あり長整数型(32bit) 0~+4294967295
float 短精度浮動小数点型(32bit)

処理系依存

double 倍精度浮動小数点型(64bit)

処理系依存

 

符号あり、なしとは何か?

符号ありとはプラスとマイナスの値を表現できることを意味します。最上位ビット(黄色セル)が0なら正の数、1なら負の数を表します。

一方、符号なしとは8ビット全てを使って値を表現します。

ビットパターン 符号あり(2の補数) 符号なし
00000000 0 0
00000001 1 1
01111110 126 126
01111111 127 127
10000000 -128 128
10000001 -127 129
10000010 -126 130
11111110 -2 254
11111111 -1 255

≫参考:符号付数値表現(Wikipedia)

 

変数にはスコープ記憶クラスという概念があり、参照できる範囲と保存する領域が定められています。

変数 スコープ 記憶クラス
a グローバル(プログラム全体) スタティック領域(永続的)
b グローバル(ファイル全体) スタティック領域(永続的)
c ローカル(main関数内) スタック領域(局所的)
d ローカル(main関数内) スタティック領域(永続的)
e ローカル(main関数内) ヒープ領域(mallocで獲得しfreeで返却する)
f ローカル(if文内) スタック領域(局所的)

 

型修飾子について

変数の型の前に付けることで型を修飾できます。

型修飾子 意味
signed, unsigned

データの符号の有・無を指定できます。

sigined → 符号あり

unsigned → 符号なし

short, long

intを修飾します。

short int aaa; → short aaa;に省略できる。

long int bbb; → long bbb;に省略できる。

auto

オート変数。ローカル変数のことです。関数呼び出し時に確保されたスタック領域に割り当てられます。

C言語は関数内で変数を定義するとローカル変数になるので指定不要(使わなくてよい)。B言語との互換性のために残された修飾子のようです。

register

レジスタ変数を定義します。

CPUによって仕様が異なりますが、高速アクセスが可能なSRAM領域にマッピングされた汎用レジスタが用意されていることが多くregister指定した変数は汎用レジスタに割り付けようとします。が、汎用レジスタに空きがないと普通のDRAMにマッピングされます。

extern

externを付けることでグローバル変数を他ファイルから参照できます。

externが無いと他ファイルからグローバル変数を参照できずコンパイル時に未定義エラーになります。

const

定数を作るときに指定します。

const int aaa = 123; → 以降値を変更できない。

static

staticを付けることで局所化できます。プログラムの複雑化を防止するのに役立ちます。

関数宣言の前につけると、ファイル内でのみ参照できる関数になります。

関数外(グローバル領域)に定義されたstatic変数は、ファイル内でのみ使えるグローバル変数になります。

関数内で定義されたstatic変数は、関数内でのみ参照できるグローバル変数になります。これ意外に知らない人多いです。関数内で定義されたstatic変数は値を永続的に保持するためリエントラント(再入可能)性がなくなります。リエントラント性とは複数のスレッドなどから同時に呼ばれても同じ動作がでことを意味しますが、static変数の値が呼ばれる度に変化するので動作が毎回変わります。リエントラント性がない関数は一般的にスレッドセーフでない(スレッドで使えない)関数になります。

 

③定数(リテラル)

定数(リテラル)とは固定値のことです。

以下の例のように「#defineマクロで値を定義する方法」と「constを付けた変数を定義して固定値を設定する方法」があります。

定数(定数)はコンパイル時に決定され書き換えできません。#defineマクロはプリプロセス時に固定値(リテラル)が確定しますし、constを付けた変数を書き換えようとするとコンパイルエラーが出ます。

 

④分岐処理

if~else if~else

条件によって処理を変えることができます。

 

switch文

変数の値によって処理を分岐するときに使います。

case1: case2:のようにbreakを省略してcase文を連続で書くのをフォールスルーと言います。意図的にフォールスルーするのは良いのですが単にbreak忘れでもコンパイルエラーにならないので注意しましょう。バグの元です。

 

三項演算子

条件文 ? 条件文が真のときの処理 : 条件文が偽のときの処理; という構文になります。

以下の例はparamが0以上ならそのままaに代入。paramが0より小さいならマイナスをつけてaに代入しています(絶対値が得られます)。

三項演算子を使うことで行数を減らすことが出来ますが、直観的にわかりにくいし、デバッガでステップ実行したときに値の変化を追いにくいのであまりオススメしません。

 

⑤反復(ループ)処理

for文

for( 初期化処理; 条件文; ループ毎の終了処理 ){ 処理 } という構文です。

最初にiという変数を0に初期化。iが10未満ならiの値と半角スペースをprintfしてiをインクリメント(+1)。iが10になったらループを抜けます。

実行すると0 1 2 3 4 5 6 7 8 9 と表示されます。

 

while文

while( 条件文 ){ 処理 } という構文です。

ループに入る前にiという変数を定義して0に初期化。

iが10未満ならiの値と半角スペースをprintfしてiをインクリメント(+1)。iが10になったらループを抜けます。

実行すると0 1 2 3 4 5 6 7 8 9 と表示されます。

do while文

do { 処理 } while( 条件文 ); という構文です。

ループに入る前にiという変数を定義して0に初期化。

iの値と半角スペースをprintfしてiをインクリメント(+1)。iが10になったらループを抜けます。

実行すると0 1 2 3 4 5 6 7 8 9 と表示されます。

do whileは直観的にわかりにくいため、あまりオススメしません。

continue

ループの中の処理を実行したくないときはcontinueします。

以下の例はiが10未満ならprintfをするループですが、iが5のときはprintfしたくない場合continueします。

実行すると0 1 2 3 4 6 7 8 9 と表示されます(5はprintfされません)。

 

break

ループを途中で抜けるときはbreakします。

以下の例はiが10未満ならprintfをするループですが、グローバル変数errが0でない(エラーが発生した)場合はループを抜けます。ループ処理中に緊急事態が発生したときによくやる手法です。

例えばiが8のときにerrがセットされた場合、0 1 2 3 4 5 6 7 と表示されたところでbreakが呼ばれループを抜けます。

⑥演算子

演算子には優先順位と結合規則があります。同じ優先順位の場合、結合規則の方向(←なら右から左)に計算がされます。

優先順位 結合規則 種別 構文 意味
1 左→ その他 a() 関数呼び出し
1 左→ その他 a[x] 配列添え字
1 左→ その他 a.x 構造体実体のメンバ参照
1 左→ その他 a->x 構造体ポインタのメンバ参照
1 左→ 算術演算子 a++ +1
1 左→ 算術演算子 a-- -1
2 ←右 算術演算子 ++a +1
2 ←右 算術演算子 --a -1
2 ←右 算術演算子 +a
2 ←右 算術演算子 -a
2 ←右 論理演算子 !a 否定
2 ←右 ビット演算子 ~a ビット反転
2 ←右 その他 *a ポインタ
2 ←右 その他 &a アドレス
2 ←右 その他 sizeof( a ) メモリサイズ参照
3 ←右 型変換演算子 (a)x キャスト
4 左→ 算術演算子 a * x
4 左→ 算術演算子 a / x
4 左→ 算術演算子 a % x
5 左→ 算術演算子 a + x
5 左→ 算術演算子 a - x
6 左→ ビット演算子 a << x 左ビットシフト
6 左→ ビット演算子 a >> x 右ビットシフト
7 左→ 比較演算子 a < x aはxより小さい
7 左→ 比較演算子 a > x aはxより大きい
7 左→ 比較演算子 a <= x aはx以下
7 左→ 比較演算子 a >= x aはx以上
8 左→ 比較演算子 a == x aとxは一致
8 左→ 比較演算子 a != x aとxは不一致
9 左→ ビット演算子 a & x ビットAND
10 左→ ビット演算子 a ^ x ビットXOR
11 左→ ビット演算子 a | x ビットOR
12 左→ 論理演算子 a && x aかつx
13 左→ 論理演算子 a || x aまたはx
14 ←右 その他 a ? x : y aが真ならx偽ならy
15 ←右 その他 a = x aにxを代入
15 ←右 算術演算子 a += x aにa+xを代入
15 ←右 算術演算子 a -= x aにa-xを代入
15 ←右 算術演算子 a *= x aにa*xを代入
15 ←右 算術演算子 a /= x aにa/xを代入
15 ←右 算術演算子 a %= x aにa%xを代入
15 ←右 ビット演算子 a <<= x aにa<<xを代入
15 ←右 ビット演算子 a >>= x aにa>>xを代入
15 ←右 ビット演算子 a &= x aにa&=xを代入
15 ←右 ビット演算子 a |= x aにa|=xを代入
15 ←右 ビット演算子 a ^= x aにa^=xを代入
16 左→ その他 a, b, c 列挙

 

まとめ

中編に続きます。

関連記事

【初心者向け】C言語の基本的な文法(前編)

【初心者向け】C言語の基本的な文法(中編)

【初心者向け】C言語の基本的な文法(後編)

  • この記事を書いた人
  • 最新記事

ペイヴメント

ペイヴメントのエンジニア塾(当ブログ)では20年以上の経験から得られたプログラミング系ノウハウについてベテランにも満足して頂けるような内容の濃いコンテンツを初心者にも分かりやすい形で日々発信しています。【経歴】ベンチャーのソフトハウスで4年勤務後、精密機器メーカーのソフト開発部門に勤務し今に至ります。

-Linux, Windows, 初心者向け

Copyright© ペイヴメントのエンジニア塾 , 2020 All Rights Reserved.