C言語
関数一覧
関数の作成、呼び出し
プロトタイプ宣言
関数の定義は、原則として main 関数の上に書く必要があります。
main 関数の下に関数定義を書きたい場合には、次のようにプロトタイプ宣言を記述する必要があります。
#include <stdio.h>
// プロトタイプ宣言
int sum(int, int);
int main(void)
{
int n = sum(300, 200);
printf("nの値 : %d\n", n);
return 0;
}
int sum(int x, int y)
{
return x + y;
}
プロトタイプ宣言で、変数名を一緒に記述することもできます。
※下記のように、変数名 (a と b) は下の関数定義のもの (x と y) と同じでなくても構いません。
#include <stdio.h>
// 変数名を記述したプロトタイプ宣言
int sum(int a, int b);
int main(void)
{
int n = sum(300, 200);
printf("nの値 : %d\n", n);
return 0;
}
int sum(int x, int y)
{
return x + y;
}
引数の使い方
桁数の指定(printf()関数)
指定されたストリームから文字列を読み込む(fgets関数)
数値を文字列に変換して他の変数に代入する(sprintf)
標準入力を任意のデータ型で変数に格納する(scanf)
文字列を特定のフォーマットに変換してデータを取り出して他の変数に格納する(sscanf関数)
基本的な読み込み、複数の数値を読み取る、エラーハンドリング、ユーザー入力のパース、日付と時刻の読み込み
代入する変数に&をつける理由
文字列の分割、結合、追加(strtok、strcat関数)
文字の追加
文字列の分割(strtok)
strtok 関数は、C言語で文字列をトークン(部分文字列)に分割するために使用される標準ライブラリ関数です。トークンは、指定された区切り文字(デリミタ)によって分割されます。この関数は、文字列を順番に分割していくため、複数回呼び出すことで文字列全体をトークン化できます。
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, world! How are you?";
char *delimiter = " ,!?"; // スペースとカンマ、感嘆符、疑問符を区切り文字として指定
char *token;
// 最初のトークンを取得
token = strtok(str, delimiter);
// トークンがNULLになるまでループ
while (token != NULL) {
printf("Token: %s\\n", token);
// 次のトークンを取得
token = strtok(NULL, delimiter);
}
return 0;
}
このコードを実行すると、次のようにトークンが順番に表示されます
Token: Hello
Token: world
Token: How
Token: are
Token: you
■詳細な説明
- 最初の呼び出し: 最初の呼び出しでは、分割対象となる文字列(
str
)と区切り文字(delimiter
)をstrtok
に渡します。strtok
は、最初のトークンを見つけて、そのトークンの先頭アドレスを返します。トークンの末尾には自動的に'\\\\0'
が挿入され、元の文字列が変更されます。 - 2回目以降の呼び出し:
strtok
を再度呼び出すときには、文字列の代わりにNULL
を渡します。これは、前回の呼び出しで得られた位置から続けて次のトークンを探すことを意味します。 - 終了条件: すべてのトークンが処理されると、
strtok
はNULL
を返し、トークン化の終了を示します。
■注意点
strtok
は元の文字列を変更するため、オリジナルの文字列を保持したい場合は、文字列のコピーを作成してから使用してください。strtok
はスレッドセーフではありません。複数のスレッドで同時に使用する場合、各スレッドは異なる文字列を処理するか、代わりにスレッドセーフなバージョン(例:strtok_r
)を使用する必要があります。
■まとめ
strtok は、文字列を区切り文字に基づいて分割するための便利な関数ですが、使用時には元の文字列が変更される点や、マルチスレッド環境での注意点に留意する必要があります。
文字列をコピーする(strcopy)
文字列同士が同じ文字列か比較する(strcmp)
※strcmp関数を使用するには下記コードで<string.h>を読み込む必要がある
#include<string.h>
文字列内に任意の文字列が含まれているかをチェックする(strstr)
文字列の先頭から指定した文字が最初に現れるまでの長さを返す(strcspn)
任意の文字列を2,8,10,16進数に変換する(strtol)
絶対値を計算する関数(abs/labs/fabsf/fabs)
2乗の計算を行う(pow)
指定した文字が数字(10進数)かどうかを判定する(isdigit)
ログを出力する(syslog)
ランダムな値の作り方(rand()関数)
#include <stdlib.h>
#include <time.h>
int main(void){
srand((unsigned int)time(NULL));
//1~12までのランダムな値を生成しplace変数に代入
int place = rand() % 12+ 1;
配列のコピー(memcpy関数)
※memcpy関数を使用するには下記コードで<string.h>を読み込む必要がある
#include<string.h>
動的なメモリ領域を確保する(melloc関数)
ファイルを開く、閉じる(fopen・fclose関数)
ファイルに書き込みを行う(fputc・fputs・fprintf関数)
ファイルの内容を読み込む(fgetc・fgets・fscanf関数)
実装ノウハウ一覧
スタック・キューの作り方
スタックとキューのイメージ
スタックは、最後に追加したデータを最初に取り出すことのできる、「後入れ先出し」のデータ構造です。
後入れ先出しは、”Last In, First Out” の頭文字をとって LIFO と呼ばれます。
キューは、最初に追加したデータを最初に取り出すことのできる、「先入れ先出し」のデータ構造です。
先入れ先出しは、”First In, First Out” の頭文字をとって FIFO と呼ばれます。
スタックとキューの作り方
文字列から改行文字を消し方
複数の数から最大・最小値を求める
小文字と大文字を変換する
ループ処理一覧
while文について
do-while文について
for文について
その後の処理をスキップし、ループの最初に戻る(continue文)
条件式一覧
if文について
条件によってプログラムをカットする#ifdef
switch-case文について
条件演算子(三項演算子)で短く条件式を書く
ポインタについて
1章ポインタとはなにか、何のために使うのか、どのように使うのか
2章ポインタ変数の定義や*の意味、変数との関係
3章NULLポインタについてとその使い方
4章配列に対してのポインタの使い方
5章ポインタから構造体を扱う場合(アロー演算子、間接参照演算子)
6章ポインタ変数のサイズと加減乗除算の結果と意味
7章ポインタのポインタとは
8章関数ポインタについて
9章ポインタを使った文字列制御
配列について
配列の基本とコピー
2次元配列について
3次元配列について
構造体を含んだ配列を作る
構造体の配列は、他のデータ型 (int や char など) のときと同じように作成できます。
#include <stdio.h>
typedef struct {
char name[20];
int attack;
} Enemy;
int main(void)
{
Enemy enemies[3]; // 構造体の配列
}
○ typedef を使わない場合でも、配列を作成できます。
#include <stdio.h>
struct Enemy {
char name[20];
int attack;
};
int main(void)
{
struct Enemy enemies[3]; // 構造体の配列
}
入力時・出力時のフォーマット指定子、データ型について
入力時・出力時フォーマット指定子について
データ型について
マクロについて(#define・#include)
指定したファイル内容をコピーペーストする(#include)
定数に名前を定義する(#define)
修飾子について(static・typedef)
変数や関数を他のソースファイルが参照できなくする(static)
グローバル変数の前につける→他ファイルから参照されなくなる
ローカル変数の前につける→ローカル関数を抜けても変数が維持される
(通常ローカル変数は一時的に使用したいだけなのでスタック領域に作られるが、staticをつけることによりスタック領域外に作られる)
データ型に新しい名前を付ける(typedef)
別のデータ型に変更するキャストについて
構造体について
共用体について
ビットフィールド、ビット演算について
ハンドルの作成方法
ビット演算・シフト演算について
C言語における「|」演算子は、「ビットごとの論理和(OR)」を行う演算子です。これは、二つの整数の各ビットを比較し、どちらかのビットが1であれば、結果のビットを1にするという動作をします。以下は具体的な例です。
int a = 5; // 2進数で 0101
int b = 3; // 2進数で 0011
int result = a | b; // 結果は 0111 (2進数) = 7
a
のビット列:0101
b
のビット列:0011
- これらのビットごとに「|」演算を行うと、
0111
になり、10進数では7になります。
このように、「|」演算子は、ビット操作でよく使用され、複数のフラグをまとめて扱うときなどに便利です。また、ビットごとの操作は、組み込みシステムや低レベルのハードウェア制御など、C言語が使われる分野で重要な役割を果たします。
重複しない連番を作り出すenum列挙型
変数について
ローカル変数とグローバル変数のスコープについて
変数には グローバル変数 と ローカル変数 の 2 種類があります。 ローカル変数は、スコープ内でのみアクセス(代入と参照)可能な変数で、関数内や for 文、if 文などの中での状態を記憶するために使用されます。 グローバル変数は、プログラム全体からアクセス可能な変数で、プログラム全体の状態を記憶するために使用されます。 グローバル変数とローカル変数を適切に使い分けることで、プログラムのミスを減らすことができるでしょう。 アニメーションやユーザーインタラクションの状態管理にはグローバル変数を使い、それ以外にはローカル変数を使うのが基本です。
以下のように、アクティブモードにおいて関数の外に宣言されているものがグローバル変数、それ以外がローカル変数になります。
int a = 123; // aはグローバル変数
void setup() {
noLoop();
float b = 4.56; // bはローカル変数
println(a, b);
}
void draw() {
float b = 3.14; // bはローカル変数
for (int i = 0; i < 10; ++i) { // iはローカル変数
String s = "value: "; // sはローカル変数
println(s + (a * i + b));
}
}
変数が予期せぬ外部要因によって変更される可能性があることをコンパイラに伝えるvolatile
変数を他のファイルで使用できるようにするextern宣言
文字、文字列について
ポインタを使った文字列制御
組み込み開発手法
命令コマンド・レジスタ・メモリ・セクションの調べ方
命令コマンド:各製品のユーザマニュアルソフトウェア編を参照
レジスタ・メモリ:各製品のユーザマニュアルのハードウェア編を参照
セクション:各製品のコンパイラユーザマニュアルを参照
セクションとは
プログラムコードの中でもデータの種類によって整理整頓されている。この分けられているエリアをセクションという。
レジスタの役割と制御方法
メモリについて
プログラムメモリについて(関数や定数等書き換えないデータの領域)
スタックメモリについて(ローカル変数や引数を一時的に使用するための領域)
静的メモリについて(グローバル変数などの関数処理後もメモリ領域を確保する領域)
ヒープ(動的)メモリ(malloc関数でプログラム実行中に確保したいデータサイズに合わせて確保する領域を柔軟に変えれる)
ファイルの分割方法
ファイル分割の基準
モジュール分割の考え方
ヘッダファイルの書き方
CPUについて
CPUはROMから命令を読み出し、取り出した命令を解読し、RAMに展開することで演算処理を行う。
constなどの定数はROM内に記録されており、変数は使用する際にRAMやCPU内の汎用レジスタやスタックれに展開され使用後はメモリを開放し、メモリの容量を空ける。 グローバル変数などはRAMに展開する必要があるが、ローカル変数は一時的に展開できればよいのでCPUの中の汎用レジスタやスタックレジスタにも展開することが出来る。(どの領域に割り当てるかはコンパイラが判断しているが、自分でも決めることが出来る。)
CPUレジスタについて(CPU内にあるレジスタ)
汎用レジスタについて
汎用レジスタは主にメモリのデータを一時的に格納し、演算をする場所として使われる
また、メモリの番地も格納することもあり、ポインタのような使い方もする。
プログラムカウンタについて
次に実行する命令の番地を格納している。カウンタの値は命令のデータサイズ文進。
プログラムカウンタはCPUの電源が入れられた直後に初期化され基本は0番地にリセットされる
スタックポインタ
プログラム実行時に演算や関数呼び出し、割り込みが発生した際に一時的にデータをスタック領域(RAMの最後の番地からデータを格納していく)に退避した際のデータのアドレスのことを言う。引数やローカル変数などの一時的に必要なデータに関してはこのスタック領域に作られる。
フラグレジスタ
CPU周辺機能
通信機能について
UARTについて
PCIe・パラレルIFについて
AXIについて
データ転送機能について
DMA転送機能
■転送設定手順
①転送サイズを設定する
➁転送元アドレス、転送先アドレスを設定する
③転送方法を決める(シングル、チェイン、マルチブロックなど)
④ベースアドレスを変えることでチャネルやA面・B面に対しての設定を行える
PCIeDMA
①ディスクリプタという転送するためのSRC、DST、転送サイズなどの情報を記載するエリアを作るアドレスを設定
➁設定したディスクリプタのアドレスに上記の情報に加え、このディスクリプタの転送が終了した次に実行したいディスクリプタのアドレスを指定してディスクリプタを生成する。そのご作成したディスクリプタのアドレスに1.と同じ設定を記載する。
QSPI-Flashコントローラ
①使用するデータ線数、ボーレートなどの情報をレジスタに設定する
➁QSPI-Flashコントローラのデータバッファにフラッシュに送信するコマンドデータを格納しておく
DW-QSPI-Flashコントローラ
①使用するデータ線数、ボーレートなどの情報をレジスタに設定する
➁QSPI-Flashコントローラのデータレジスタにフラッシュに送信するコマンドデータを格納しておく(この時データレジスタに書き込んだデータはFIFOに送られる
③SERを開始することでDR→FIFO→Flash間でコマンド情報の送信やデータのやり取りを行う。
CRC機能
タイマー・カウンター機能
インターバルタイマー機能
一般的なタイマの設計方法はマイコンのクロックソースf(MHz)をN分周したものをさらにプリスケーラという分周器により、M分周させる。 この信号をタイマカウント設定値Xをカウントダウンさせることにより、 割り込み周期を設計する。式としては以下となる。 クロックソースf=20MHz、分周比N=8
プリスケーラの分周比M=250
タイマカウントX=200(上記で分周したクロックが200回カウントすると割り込み発生)
割込み周期=1/20MHz ×8×250×200=20ms(20msごとに割込み発生)
WDT(ウォッチドッグタイマ)機能
GPIO(汎用入出力)機能
A/D変換D/A変換
非同期通信機能
①送信する場合はマスタ基板の送信用バッファにデータをセット、受信する際は受信用バッファにデータが送られる
➁RW設定、バッファでやり取りするのか直接データを指定するのかなどの設定をレジスタに設定する。
③RWしたいイニシエータ側のアドレスを専用のメモリマップでWORDアドレスで指定する(指定したWORDアドレスがそれに対応したメモリマップに記載のイニシエータ側の物理アドレスになる)
ロジアナ機能
①観測するチャンネル、トリガにする信号、トリガ検出までの回数、トリガ後のトレース終了までのイベント数、観測する信号のマスク設定、トレースしたデータを書き込むメモリのアドレスとサイズを指定する
➁ロジアナを同時開始するか個別に開始する。個別に開始した際はトレースしたデータがトレース用のメモリサイズをオーバーした際にトレースメモリの最初にもどりトレースデータを新しい情報に上書きするラップアラウンドが発生する。両コアを同時に開始した際には、このラップアラウンドが発生せず、どちらかのトレースメモリがいっぱいになった時点でトレース終了する。