- メイクファイル
1.1 構造:
ターゲット:前提条件
指図
1.2 gcc コンパイル: -g、-o、-c、-D、-w、-W、-Wall、-O3
-c: ソース ファイルはコンパイルおよびアセンブルされますが、リンクされません。
例:
gcc -c テスト.cpp -o テスト
-c の後に複数のソースファイルが続く
-cの後に複数のソース ファイルが続く場合、ソース ファイルごとに.oファイルが生成されますが、現時点では-oは使用できません。
参考リンク:gcc コンパイルオプション -o と -c_gcc の紹介 -o_chengqiuming のブログ - CSDN Blog
1.3 オートメーション変数
オートメーション変数 |
説明する |
$@ |
オブジェクトファイルを示します |
$% |
対象ファイルが静的ライブラリファイルの場合、静的ライブラリのメンバ名を表します。 |
$< |
最初の依存ファイルを示します。 |
$^ |
すべての依存ファイルを表します。 |
$? |
ターゲット ファイルよりも新しいすべての依存ファイルのリスト。 |
$+ |
「$^」と似ていますが、依存ファイルの重複した出現を保持します。主にプログラムをリンクする際のライブラリの相互参照の際に使用されます。 |
$* |
パターンルールおよび静的パターンルールでは、「stem」を表します。「幹」とは、対象パターンの「%」で表される部分です(ファイル名にディレクトリが存在する場合、 |
テスト:test.o test1.o test2.o
gcc -o $@ $^
テスト.o:テスト.c テスト.h
gcc -o $@ $<
test1.o:test1.c test1.h
gcc -o $@ $<
test2.o:test2.c test2.h
gcc -o $@ $<
GNU でこれらの変数に文字「D」または「F」を追加すると、ファイル名を操作できる一連のバリアント自動化変数が形成されます。
Dはディレクトリ部、Fはファイル部を表します。例: $(@D)、$(@F)
1.4 オブジェクトファイルの検索
4.1 VPATH
VPATH := ソースカー
テスト:test.o
gcc -o $@ $^
最初に src ディレクトリ内のファイルが検索され、次に car ディレクトリ内のファイルが検索されます。
4.2 vpath
vpath test.c ソースカー
2 つのパスで test.c ファイルを検索します
1.5 偽りの標的
綺麗:
rm -rf *.o テスト
2、シェル
参考リンク:https://www.jianshu.com/p/74e8739ddc01
2.1 シェルスクリプト、
#!/bin/bash
「HelloWorld!」をエコーします。
2.2 フロー制御文
if – then – else – fi
そうでなければ
もしエリフ・ファイなら
for ループ
while ステートメント
until ループ (while 条件の反対)
ケース…イーサック
-eq/-ne/-gt/-ge/-lt/le
以上_
-e ファイルが存在する場合は true
-r ファイルが存在し、読み取り可能な場合は True
-w ファイルが存在し、書き込み可能な場合は True
-x ファイルが存在し、実行可能な場合は True
-s ファイルが存在し、少なくとも 1 文字が含まれている場合は True
-d ファイルがディレクトリの場合は true
-f ファイルが存在し、通常のファイルの場合は true
-c ファイルが存在し、キャラクタ型特殊ファイルの場合は true
-b ファイルが存在し、ブロック特殊ファイルの場合は True
2.3 機能
例:
#!/bin/bash
関数 timeFun(){
echo "この関数は 2 つの数値を乗算します"
echo "最初の番号を入力してください"
番号1を読む
echo " 2 番目の数字を入力してください"
num2 を読み取ります
$(( ${num1} * ${num2} )) を返す
}
楽しい時間
echo -n "入力された 2 つの数値の乗算値は$?"
3. ポインタ
C言語は他の高級プログラミング言語に比べてコンピュータハードウェアをより効率的に動作させることができ、コンピュータハードウェアの動作命令はアドレスに大きく依存します。
ポインタはアドレスを操作する方法を提供するため、ポインタを使用すると、C 言語がコンピュータの基盤となるハードウェア上でより効率的に動作できるようになります。さらに、配列はポインターを使用してより簡単に操作できます。ある意味、ポインタはC言語の本質とも言えます。
3.1 メモリとアドレス
参考リンク:http://c.biancheng.net/c/pointer/
(1) &: 変数アドレスを取得
(2) ポインタ変数の定義: int *p など。
(3) 「ワイルド」ポインタ
int *pi,a; //pi は初期化されておらず、正当なポインタがなく、「ワイルド」ポインタです
*pi=3; //実行時エラー! 「ワイルド」ポインタが指すスペースではストレージ操作を実行できません。このステートメントは、「ワイルド」ポインタpiが指すランダムな空間に3 を格納しようとすると、実行時エラーが発生します。
(4) ポインタと配列
配列ポインタ: 例 int (*p)[5]; 2 次元配列を表すことができます
#M3 を定義
#define N 4
int a[M][N],i,j;
int (*p)[N]=a; // 2 つのステートメントと同等int (*p)[N] ; p=a;
ポインタ配列: 例 int * a[5];
int a0、a1、a2、a3、a4;
a[0]=&a0;
a[1]=&a1;
...
a[4]=&a4;
3.2 関数ポインタ
参考リンク:https://blog.csdn.net/Jacky_Feng/article/details/108953519
(1) 関数ポインタの定義
プログラム内で関数が定義されている場合、コンパイル時にコンパイラは関数コード用の記憶領域のセクションを割り当てます。この領域の開始アドレス (エントリ アドレスとも呼ばれます) は、この関数のポインタと呼ばれます。
例:
int func(int a,int b);//関数宣言
int (*p) (int , int );//パラメータ リストをint型の 2 つの変数として定義し、戻り値の型はint型の関数ポインタpとします。
p=func ; //関数ポインタp は関数funcの開始アドレスを指します
(2) 関数ポインタの適用
関数ポインタ p が指す関数を呼び出します。
(*p )(3, 5);
3.3 コールバック関数
プログラムはこの関数の関数ポインタを他の関数にパラメータで渡しますが、その関数内でこの関数ポインタを呼び出すことはこの関数を呼び出すことと同じであり、このような処理をコールバック、呼び出される関数をコールバック関数と呼びます。
例:
#include <iostream>
名前空間 std を使用します。
//1.コールバック関数を定義する
void print(int n)
{
for (int i = 0; i < n; i++) {
cout << "hello world" << endl;
}
}
//2.コールバック関数のプロトタイプ(関数ポインタ)を定義する
typedef void (*CallbackFun)(int);
//3.登録コールバック関数を定義する
void registCallback(CallbackFun コールバック,int n)
{
コールバック(n);
}
int main()
{
//4.印刷関数ポインタをパラメータとして登録関数registerCallbackに渡し、コールバックを呼び出します。つまり、印刷関数が実行されます。
registCallback(print, 10);
}
4. マルチスレッドとマルチプロセッシング
スレッドシステムの場合:
(1) プロセスはリソース割り当ての独立した単位です
(2) スレッドはリソース スケジューリングの独立した単位です
スレッドレス システムの場合:
(1) プロセスは、リソースのスケジューリングと割り当ての独立した単位です。
4.1 プロセス間の通信方法とそのメリット・デメリット
パイプライン (PIPE )
(1) ウェルノウンパイプ:無関係なプロセス間の通信を可能にする半二重通信方式。
①メリット:あらゆる関係のプロセス間の通信が実現できる。
②欠点: a. システム内での長期保存、不適切な使用によりエラーが発生しやすくなる; b. バッファが限られている。
(2) 無名パイプ:血縁関係のあるプロセス(親子プロセス)間でのみ使用できる半二重通信方式。
①メリット:シンプルで便利。
② デメリット: a. 一方向通信に限定される; b. プロセスとその関連プロセス間でのみ作成できる; c. バッファが制限される。
セマフォ (セマフォ): 複数のスレッドによる共有リソースへのアクセスを制御するために使用できるカウンター。
- 長所: プロセスを同期できます。
② デメリット:セマフォが限られている。
シグナル (Signal ):イベントが発生したことを受信プロセスに通知するために使用される、より複雑な通信方法。
メッセージ キュー (メッセージ キュー):メッセージのリンクされたリストであり、カーネルに格納され、メッセージ キュー識別子によって識別されます。
- 利点:同期問題を考慮することなく、任意のプロセス間の通信を実現でき、システムコール関数によりメッセージ送受信の同期を実現できるので便利です。
② デメリット:情報のコピーには余分な CPU 時間がかかるため、大量の情報や頻繁な操作には適していません。
共有メモリ (Shared Memory ):他のプロセスがアクセスできるメモリのセクションをマップします。この共有メモリは 1 つのプロセスによって作成されますが、複数のプロセスがアクセスできます。
- 利点: コピーする必要がなく、高速で大量の情報が得られます。
② デメリット: a. 共有空間バッファをプロセスの仮想アドレス空間に直接接続することで通信が実現されるため、プロセス間の読み取りおよび書き込み操作の同期が取れない; b. メモリ バッファを使用して情報を直接交換するため、プロセスの実体メモリ コンピュータ内に存在し、同じコンピュータ システム内の多くのプロセスでのみ共有できるため、ネットワーク通信には不便です。
ソケット (Socket ):異なるコンピュータ間のプロセス通信に使用できます。
①メリット:
a. 送信データはバイトレベルであり、送信データはカスタマイズ可能であり、データ量が少なく効率が高い。
b. データ送信時間が短く、パフォーマンスが高い。
c. クライアントとサーバー間のリアルタイムの情報対話に適しています。
d. 暗号化が可能であり、データのセキュリティが強力です。
② デメリット: 送信されたデータを分析し、アプリケーションレベルのデータに変換する必要があります。
4.2 スレッド間の通信方法
4.2.1 ロック機構
ミューテックス/数量(ミューテックス)、リーダライタロック(リーダライタロック)、スピンロック(スピンロック)、条件変数(コンディション)を含む
- ミューテックス/ボリューム (ミューテックス): データ構造が排他的な方法で同時に変更されることを防ぐメソッドを提供します。
ミューテックス機構には主に次の基本機能が含まれます。
- ミューテックスの初期化: pthread_mutex_init()
- ミューテックスロック: pthread_mutex_lock()
- ミューテックス判定ロック:pthread_mutex_trylock()
- ミューテックスロック: pthread_mutex_unlock()
- ミューテックスの削除: pthread_mutex_destroy()
- リーダー/ライター ロック (リーダー/ライター ロック): 書き込み操作は相互に排他的ですが、複数のスレッドが共有データを同時に読み取ることができます。
読み取り/書き込みロック メカニズムには主に次の基本機能が含まれます。
- int pthread_rwlock_init(pthread_rwlock_t * rwlock, const pthread_rwlockattr_t * attr);
- int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
- int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
- int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
- int pthread_mutex_timedrdlock(pthread_rwlock_t * rwlock,const struct timespec * tsptr);
- int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
- int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
- int pthread_mutex_timedwrlock(pthread_rwlock_t * rwlock,const struct timespec * tsptr);
- int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
- スピン ロック (スピン ロック) はミューテックスに似ており、どちらも共有リソースを保護します。ミューテックスは、リソースが占有され、申請者がスリープ状態になるときであり、一方、スピン ロックは、保持者がロックを解放したかどうかを確認するためにループします。
スピンロック機構には主に次の基本機能が含まれています。
- int pthread_spin_destroy(pthread_spinlock_t *lock);
- int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
- int pthread_spin_lock(pthread_spinlock_t *lock);
- int pthread_spin_trylock(pthread_spinlock_t *lock);
- int pthread_spin_unlock(pthread_spinlock_t *lock);
- 条件変数 (条件): 特定の条件が true になるまで、プロセスをアトミックにブロックできます。条件のテストは、ミューテックスの保護の下で行われます。条件変数は常にミューテックスとともに使用されます。
マルチスレッド セマフォには次の基本機能が含まれます。
- int sem_init(sem_t *sem, int pshared, unsigned int val);
- int sem_wait(sem_t *sem);
- int sem_post(sem_t *sem);
- int sem_destory(sem_t *sem);
4.2.2 セマフォの仕組み(セマフォ)
(1) 名前のないスレッドセマフォ
(2) 名前付きスレッドセマフォ
シグナルメカニズム(Signal):プロセス間の信号処理に類似
バリア: バリアにより、各スレッドは、連携するすべてのスレッドが特定のポイントに到達するまで待機し、そのポイントから実行を継続できます。
スレッド間の通信の目的は主にスレッドの同期であるため、スレッドにはプロセス通信のようなデータ交換のための通信機構はありません。
プロセス間のプライベートおよび共有リソース
プライベート: アドレス空間、ヒープ、グローバル変数、スタック、レジスタ
共有: コードセグメント、パブリックデータ、プロセスディレクトリ、プロセスID
スレッド間のプライベートおよび共有リソース
プライベート: スレッドスタック、レジスタ、プログラムカウンター
共有: ヒープ、アドレス空間、グローバル変数、静的変数
4.3 マルチプロセスとマルチスレッドの比較、長所と短所、および選択
1. コントラスト
2. メリットとデメリット
3. 選択します
(1) 頻繁に作成、破棄する必要がある優先スレッド
(2) 計算量の多いスレッドを優先して使用する
(3) 関連性の高い処理はスレッドを使用し、関連性が弱い処理はプロセスを使用します。
(4) マルチマシン分散にはプロセスを使用し、マルチコア分散にはスレッドを使用するように拡張できます。
(5) すべての要件が満たされている場合は、最も使い慣れた、最も得意な方法を使用してください。
五、Linuxネットワークプログラミング
5.1 TCP
5.1.1 TCPネットワークモデル
Linuxで TCP サーバーを作成するには、次の 6 つの手順があります。
ソケット - ソケットを作成します
binding - ホストとポートをバインドします
listen -- リスニングソケットを設定します
accept - クライアント接続を受け入れ、新しいソケットを生成します
読み取り/書き込み – データの送受信
close - ソケットを閉じます
クライアントの作成は主に次の手順に分かれます。
ソケット -- ソケットを作成します
connect -- サーバーにアクティブに接続します
書き込み/読み取り -- データの送受信
close -- ソケットを閉じます
- ソケット - ソケットを作成します
関数プロトタイプ: int ソケット(int ドメイン、int 型、int プロトコル);
パラメータの説明:
ドメイン: プロトコル ファミリ、通信に使用されるプロトコル ファミリを指定します。一般的なオプションは次のとおりです。
AF_UNIX、AF_LOCAL :ローカル通信。ローカルプロセス/スレッド間の通信に使用されます。
AF_INET:IPv4インターネットプロトコル
AF_INET6:IPv6インターネットプロトコル
type: ソケット タイプ、一般的に使用されるオプションは次のとおりです。
SOCK_STREAM: TCP に一意に対応するストリーム ソケット。
SOCK_DGRAM: UDP に一意に対応するデータグラム ソケット。
SOCK_RAW: 未加工 (透明) ソケット。
プロトコル: 通常は 0 を入力します。タイプ type が SOCK_RAW の場合、このパラメータは必須です。
戻り値: 成功した場合はソケット (ファイル記述子) が返され、失敗した場合は -1 が返されます。
- binding - ホストとポートをバインドします
関数プロトタイプ: int binding(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
一般的なアドレス構造:
構造体 sockaddr {
sa_family_t sa_family; //アドレスファミリー
char in_data[14];
}
インターネットアドレス構造:
構造体 sockaddr_in {
u_short sin_family; // アドレス ファミリ、AF_INET、2 バイト
u_short sin_port; // ポート、2 バイト
構造体 in_addr sin_addr; // IPV4地址,4バイト
char sin_zero[8]; // 8 バイトはパディングとして未使用
};
IPv4アドレス構造
// インターネットアドレス
構造体 in_addr
{
in_addr_t s_addr; // u32 ネットワークアドレス
};
ローカル通信プロトコルのアドレス構造: プロセス間通信に使用可能
構造体 sockaddr_un
{
sa_family_t sun_family; //プロトコル ファミリ
char sun_path[108]; //ソケットファイルのパス
}
- listen -- リスニングソケットを設定します
パラメータ: sockfd --- ソケットファイル記述子
バックログ --- キューの長さを監視する
- accept - クライアント接続を受け入れ、新しいソケットを生成します
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
パラメータ:
sockfd --- ソケットファイル記述子
addr --- クライアント IP とポート番号
addrlen --- クライアントアドレスの長さ
注: addr と addrlen はクライアントのアドレスを取得するために使用されます。クライアントを知る必要がない場合、これら 2 つのパラメーターは NULL に設定されます。
- connect – サーバー (クライアント) にアクティブに接続します。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
パラメータ:
sockfd --- ソケットファイル記述子
addr --- サーバーのアドレス
addrlen --- アドレスの長さ
- 読み取り/書き込み – データの送受信
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
パラメータ:
sockfd --- ソケットファイル記述子
buf --- 送信データの先頭アドレス
len --- 送信されたバイト数
フラグ --- 送信メソッド(0)
size_t recv(int sockfd, void *buf, size_t len, int flags);
パラメータ: sockfd --- ソケットファイル記述子
buf --- データが格納されている空間の先頭アドレス
len --- 受信したいバイト数
flags --- 受信メソッド(0)
- close - ソケットを閉じます
- setsockopt 関数
参考リンク:https://blog.csdn.net/Mr_XJC/article/details/106788694
5.2 UDP
手順 (関数呼び出しについては TCP を参照):
(1) ソケットの作成
(2) IPバインドとポートバインド
(3) メッセージの送受信
参考リンク:Linux環境でのUDP通信_linux udp通信_workingweiのブログ - CSDNブログ
6. データ構造
参考リンク:C言語データ構造_Rising Sun Chuyang's Blog - CSDN Blog
typedef 構造体と構造体定義構造体の違い
参考リンク:【C言語】typedef structとstructの使い方の違い typedef structとdirect structの違い_Mijie's Voice Blog - CSDN Blog
struct の構文はさらに複雑なので、1 つずつ例を示してみましょう。
例一:
構造体{
文字a;
int b;
} バツ;
ここでは、2 つのメンバーを含む変数が作成されます。
1 つの文字、1 つの整数。
例二:
構造体学生{
文字名;
年齢;
};
ここでタグが作成されるので、
メンバーリストには STUDENT の名前が提供されました。
将来的には、struct STUDENT x; を通じて変数を宣言できるようになります。
次にtypedefとstructの組み合わせです。
例 3:
typedef 構造体{
文字名;
年齢;
}学生;
ここでの効果は基本的に例 2 と同じです。
STUDENT がデータ型の名前になりました。
後のステートメントは STUDENT x として直接書くことができます。
例 4:
typedef 構造体 NODE{
int データ;
構造体 NODE* 次;
}ノード;
これはリンク リスト ノードを作成する一般的な方法であり、次の 2 つのステップに分けることができます。
最初の一歩
構造体ノード{
int データ;
構造体 NODE* 次;
};
NODEという構造タイプを作成しました。
2 番目のステップ typedef NODE ノード。
データ型に NODE という名前をノードとして付けます。
注目に値するのは、
リンクリストを作成するときは、
typedef 構造体 NODE{
int データ;
構造体 NODE* 次;
}ノード;
次にポインタは struct NODE* を使用して作成されます。
以降の作成、挿入、削除、検索関数、および main 関数では、
宣言ポインタは、node* ポインタと統合されます。
遭遇した問題
- 複数のスレッドでコンパイルする場合、ライブラリのリンクが不足し、コンパイル時に -lpthread または -pthread を追加します。
例:gcc -o test.c test -lpthread
- Scanf スペースの問題、2 つの解決策
- fgets() を置き換えます。
- scanf(“%[^\n]”, msg);