C言語のスクラップ-01


タオ兄弟の100番目のオリジナル

I.はじめに

最近組み込みプロジェクトのコードを別のプラットフォームに移植していて、多くの場所でC89標準が使用されていることがわかりました。

1999年、C言語標準化委員会はC99標準をリリースしました。これには、可変長配列、柔軟な配列メンバー(構造で使用)、IEEE754浮動小数点数の改善、指定されたメンバーの初期化子、内部連想関数など、多くの機能が導入されました。不定数のパラメーターをサポートするマクロ定義、およびlong longint型と複素数型がデータ型に追加されます。

そこで最近、比較的新しいC言語の本を見つけて裏返しましたが、C99標準の一部のコンテンツを含め、よりリモートの文法の多くはめったに使用されないことがわかりました。そのため、コンテンツのこの部分を整理したいと思います。私自身この古代の言語を再編成します。

第二に、小さなテスト

1.柔軟な配列メンバー

概念を説明せずに、最初にコード例を見てみましょう。

// 一个结构体,成员变量 data 是指针
typedef struct _Data1_ {
    int num;
    char *data;
} Data1;

void demo6_not_good()
{
    // 打印结构体的内存大小
    int size = sizeof(Data1);
    printf("size = %d \n", size);

    // 分配一个结构体指针
    Data1 *ams = (Data1 *)malloc(size);
    ams->num = 1;

    // 为结构体中的 data 指针分配空间
    ams->data = (char *)malloc(1024);
    strcpy(ams->data, "hello");
    printf("ams->data = %s \n", ams->data);

    // 打印结构体指针、成员变量的地址
    printf("ams = 0x%x \n", ams);
    printf("ams->num  = 0x%x \n", &ams->num);
    printf("ams->data = 0x%x \n", ams->data);

    // 释放空间
    free(ams->data);
    free(ams);
}

私のコンピューターでは、印刷結果は次のようになります。

構造体は合計8バイトであることがわかります(int型は4バイトを占め、pointer型は4バイトを占めます)。

dataメンバーの構造はポインター変数です。これは、別のアプリケーションがスペースを使用できる必要があるためです。そして、構造体が使用された後、最初data解放され、次に構造体ポインタが解放されるams必要があります順序を間違えることはできません
このように使うのは少し面倒ですか?

したがって、C99標準では文法が定義されています。flexiblearraymember (flexible array)、コードを直接アップロードします(コンパイル時に次のコードで警告が発生した場合は、この文法に対するコンパイラのサポートを確認してください)。

// 一个结构体,成员变量是未指明大小的数组
typedef struct _Data2_ {
    int num;
    char data[];
} Data2;

void demo6_good()
{
    // 打印结构体的大小
    int size = sizeof(Data2);
    printf("size = %d \n", size);

    // 为结构体指针分配空间
    Data2 *ams = (Data2 *)malloc(size + 1024);

    strcpy(ams->data, "hello");
    printf("ams->data = %s \n", ams->data);

    // 打印结构体指针、成员变量的地址
    printf("ams = 0x%x \n", ams);
    printf("ams->num  = 0x%x \n", &ams->num);
    printf("ams->data = 0x%x \n", ams->data);

    // 释放空间
    free(ams);
}

印刷結果は次のとおりです。

最初の例はいくつかの違いがあります

  1. 構造のサイズは4になります。
  2. 構造体ポインタにスペースを割り当てる場合、構造体自体のサイズに加えて、データに必要なスペースにも適用されます。
  3. データ用に個別にスペースを割り当てる必要はありません。
  4. スペースを解放するときは、構造体ポインターを直接解放するだけです。

使いやすいですか?これは、柔軟なアレイの利点です。

構文的に言えば、柔軟な配列とは、構造内の最後の要素の数が不明な配列を指し、長さ0としても理解できるため、この構造は可変長と呼ぶことができます。

前述のように、配列名はアドレスを表します。これは定数アドレス定数です。構造体では、配列名は単なるシンボルであり、オフセットを表すだけであり、特定のスペースを占有しません。

さらに、柔軟な配列は任意のタイプにすることができますこの例では、誰もが多くの経験を積んでいます。この使用法は、多くの通信処理シナリオでよく見られます。

2.不定パラメータのマクロ定義

マクロで定義されるパラメーターの数は、printf print関数を呼び出すのと同じように、未定義にすることができます。定義するときは、3つのドット(...)使用して変数パラメーターを表すか、3つのドットの前にオプションを追加できます。変数パラメーターの名前。

変数パラメーターを受け取るために3つのドット(...)を使用する場合、次のようVA_ARGS使用して変数パラメーターを表す必要があります。

#define debug1(...)      printf(__VA_ARGS__)

debug1("this is debug1: %d \n", 1);

3つのドット(...)の前にパラメーター名を追加する場合は、使用するときにこのパラメーター名を使用する必要があり、次のようにVA_ARGS使用して変数パラメーターを表すことはできません

#define debug2(args...)  printf(args)

debug2("this is debug2: %d \n", 2);

ただし、可変パラメータの数がゼロの場合、処理に問題が生じる可能性があります。

このマクロを見てください:

#define debug3(format, ...)      printf(format, __VA_ARGS__)

debug3("this is debug4: %d \n", 4);

コンパイルと実行に問題はありません。ただし、次のようなマクロを使用する場合:

debug3("hello \n");

コンパイル時エラーが発生します:error: expected expression before ‘)’ tokenどうして?

マクロ展開後のコードを見てください(__VA_ARGS__空):

printf("hello \n",);

問題がわかりますよね?フォーマット文字列の後に余分なコンマがありますこの問題を解決するために、プリプロセッサはメソッドを提供します##記号を使用して、この余分なコンマを自動的に削除します

したがって、マクロ定義を以下に変更しても問題ありません。

#define debug3(format, ...)     printf(format, ##__VA_ARGS__)

同様に、変数パラメーターの名前を自分で定義する場合は、次のように、その前に##を追加します。

#define debug4(format, args...)  printf(format, ##args)

三、あなた自身を応援してください

この記事はまだ始まったばかりです。今後も情報を収集していきます。最終的な目標は、C言語の文法と使用法を小冊子にまとめることです。これに固執できることを願っています。


良い記事 を転送 する 必要があります;共有すればするほど、あなたは幸運になります!

スター公式アカウント、あなたは私をより速く見つけることができます!


この記事をWebサイトに転載する場合は、著者、記事のソース、および上記のQRコードを保持してください。

この記事を公式アカウントに転載したい場合は、プライベートメッセージを送信するか、メッセージを残してください。長白を開きます。



推奨読書

[C言語]
C言語ポインター-基本的な原則から高度なスキルまで
、元のgdbの基本的なデバッグ原則を非常にシンプル
で段階的分析で説明するに役立つグラフィックとコード-Cを使用してオブジェクトを実装する方法-
強力なツールのコード改善するための指向プログラミング:マクロ定義-エントリから放棄まで、C言語でsetjmpとlongjmpを使用して
例外のキャプチャとルーチンを実現します。

【アプリケーションプログラミング】
ソフトウェアアーキテクチャを階層化してモジュールに分割し、具体的に何をすべきか(1)
ソフトウェアアーキテクチャを階層化してモジュールに分割し、具体的に何をすべきか( 2)
IoTゲートウェイ開発:MQTTメッセージバスに基づく設計プロセス(オン)
IoTゲートウェイ開発:MQTTメッセージバスに基づく設計プロセス(下)
プロセス間の私のお気に入りの通信方法-メッセージバス

【オペレーティングシステム】
なぜ宇宙船やミサイルは組み込みシステムではなくシングルチップコンピュータを好むのですか?

[モノのインターネット]
暗号化と証明書に関する
ことはLUAスクリプト言語に深く入り込んでいるため、デバッグの原理を完全に理解できます。

[ナンセンス]私の失敗したキャリア経験に基づく
:職場に不慣れな技術者のためのいくつかのヒント

おすすめ

転載: blog.csdn.net/u012296253/article/details/115366870