プログラミングC:列挙型、ビットフィールド、および共用体

この記事はシリーズの一部です – どのようにプログラミングするには:Cプログラミング

序文

これまでは、基本的なデータ型、構造体、配列、ポインタなどのデータ型を集計しました。 Cで扱うデータ型は3つあり、それは列挙型、ビットフィールド型、および共用体です。 これら3つの後者はやや難解なものであり、ハードウェアやコンパイラなどを扱う場合を除いて、必ずしも多くを使用するとは限りません。 列挙型は基本的に、指定されたキーを整数または定数にマップするデータ型を指定する方法です。 ビットフィールドを使用すると、1つまたは複数のバイトのビットに複数の異なる識別子をマップとして格納できますが、その性質上、Cコンパイラ固有の可能性があります。 共用体は、異なるデータ型の後にあるメモリ内の同じスペースにアクセスできるタイプです。たとえば、2つの要素のchar配列または1つのshort intのいずれかと同じアドレスにアクセスできます。

列挙型

列挙はかなり単純な概念です。 列挙型は整数定数のシーケンスであり、各整数には名前が割り当てられます。 つまり、1の場合は「1」、2の場合は「deux」、3の場合は「3回」などの名前を使用できます。これらはデータ型に限定されているわけではなく、変数が 列挙型の名前をそれ自身に割り当てることを利用するためには列挙型を使用しますが、列挙型で定義された名前を使用して、対応する整数値を表すこともできます。 列挙は構造と非常によく似ていますが、独自の特異性を持っています。 コードスニペットは説明に役立ちます:

このコード例では、今年のすべての月の列挙を定義しました。毎月整数値を表す識別子です。実際には、各名前は最後の整数値1より大きい整数値を表します。この例では、january = 0、februray = 1、march = 3などです。コードスニペットでは、データ型としてenumを使用して変数を変数に限定する方法を示しましたが、そのデータ型スコープの列挙型名を「外側」に使用します。この例の最後のステートメントでは、mayの値を標準出力(画面)に「印刷」します。私たちはまだこのタイプの機能をカバーしていませんが、私はmyMonthの外で使うことができます。

この例では、月の名前が0の先頭から数えて対応する整数に割り当てられています。enum宣言内のその値に名前を割り当てることによって、列挙子の値を指定することは可能です。その名前の後に来るすべての識別子は、与えられた値に1を加えます。これの例は次のとおりです。

この列挙型では、最初は0になり、2番目は1になります。ただし、3になると300という値に設定されます。これにより4番目と5番目の定義が変更され、それぞれ301と302になります。 列挙型の値にのみ整数を割り当てることができます。

上のコードスニペットから、enum宣言の一般的な形式は次のようになります:

列挙は、互いに価値のあるものと干渉しない識別子のリストにしたいときに便利です。 値の代わりに別の場所にリストアップすることができる膨大な数の名前を参照したいのではなく、識別子によって参照したいとします。 列挙型はこの目的のためにうまく機能します。 一例は、コンパイラのすべてのオペレーションコードである可能性があります。 コンパイラを書いている間は、人間が読める名前を使って各オペコードを参照できますが、コンピュータには多くの価値があります。 グローバル変数と定数で同じことをすることもできますが、列挙型はこれをデータ型にパッケージ化できるため、はるかに洗練された解決策です。

列挙型は文字列ではありません

列挙子には重要な注意点があります。 プログラマーは列挙型が単なる数値の識別子であることを覚えておく必要があります。 実行中またはコンパイルされたプログラムのコンテキストでは、識別子は意味を持ちません。 つまり、プログラム操作で識別子そのものを取得することは期待できません。 たとえば、数ヶ月の列挙体に続いて、次のようなことはできません。

コードでは、myMonthには、4桁の列挙型の整数コードが割り当てられます。 myMonthは実際に識別子aprilと同じではありません。 myMonthを文字列のように割り当てることは型の不一致です。 すべての列挙子は整数です。 列挙型の値を実際に文字列にマップするには、switch文を作成する必要があります(switch文はまだ扱っていません)。列挙型が特定の値であるかどうかを調べて文字列を出力します 、またはルックアップテーブルを作成することができます。

ルックアップテーブルは一連の文字列で構成されます。これは列挙型の識別子を模倣する文字列の配列です。 月単位の列挙型のルックアップテーブルは、次のようになります。

これは、列挙子の識別子が100などの特別なものに初期化されていないために機能します。特殊な初期化があった場合、このタイプのテーブル参照は動作しにくく、特別な調整が必要でした。 このシナリオで列挙型の列挙型の値を取得する場合は、前の列挙型の列挙子に従って、次のように記述します。

組合

場合によっては、2つの異なる方法で同じデータを含むメモリを参照したいことがあります。 いくつかの例では、浮動小数点として扱うことを望みますが、文字列のように使用したい場合は、バイト単位で同じ正確なデータにアクセスします。 おそらく、倍精度の精度の書式を変更したり操作したりするには、これを実行します。 または、浮動小数点数を素早くバイトに分解して、ファイルにすばやく書き込む方法が必要なのかもしれません。 コンパイラは、ユニオンをキャッチオールの値として使用して、1つのユニオンが多くの異なるタイプのデータ構造として動作できるようにすることがあります。 これらの例は、共用体を使用する場所です。

組合は、私たちが今説明したこととまったく同じです。 以下の4つの文字として解釈可能なフロートを設定しましょう:

あなたが見ることができるように、その構造は構造体に非常によく似ています。 この例では、float fとchar ch [4]は同じスペースを占有します。 構造体のように、共用体の要素にアクセスしたい場合は、それがポインタかどうかに応じて、ドット演算子(.)または矢印演算子(->)を使用します。 ここではコードがより明確になり、共用体変数を設定し、ドット(.)演算子を使用してデータのさまざまなバイトにアクセスしましょう:

共用体変数が宣言されると、コンパイラーはメモリー内のスペースを、指定された共用体の最大メンバー(この場合はfloat)に等しくします。 私たちが24バイトの大きさの、文字配列を含む結合体のメンバーを持っていたら、そのサイズより小さいものはそのメモリ割り当てにマップされます。 つまり、与えられた任意の共用体変数のメモリーフットプリントは、共用体内の最大のデータ宣言と等しくなります。 共用体は、short intsの配列と同じメモリ空間を使いたいが、バイト単位でより細かい作業をする必要がある場合に便利です。代わりに一連の文字としてアクセスします。

ビットフィールド

Cは中間レベルの言語であるため、その機能のいくつかは正確なビット設定とビット検索を目的としています。 Cの式の記事では、より深いビット演算子について詳しく学習しますが、ここではプログラマがデータの特定のビットにアクセスできるようにする組み込みのデータ型/構造に焦点を当てます。これはビットフィールドと呼ばれ、そのサポートはお使いのコンピューティング環境とコンパイラによって多少異なります。しかし、ビットフィールドは、データの特定のビットを名前で参照したいときに便利です。ハードウェアを使って作業するとき、コンパクトな情報が返されることがあります。ここでは、さまざまな部分が1バイトの1つまたは複数のビットにエンコードされています。あるいは、各状態の変数を保持するのではなく、1バイトに圧縮したフラグ、オンまたはオフの値を設定しているので、特定のバイトの各ビットに簡単にアクセスすることができます。

ビットフィールドは、構造体(前の記事を参照してください)または共用体の中で宣言しなければなりません。このため、以下のように、ビットフィールドの基本的な一般形式を扱います。

ビットフィールドには3つの基本タイプ(C99を使用している場合は4つ)しかありません。 許可される型はint、signed、およびunsignedです(C99を使用する場合は_Bool)。 ビットフィールドをどのように利用するかを理解するために、次のバイトの情報を返すハードウェアがあれば、各ビットは何かを意味します。 Wikipediaから借用するには、6502プロセッサ(8ビット)のステータスレジスタがあるとします。 このステータスレジスタの状態を取得するたびに、各ビットから次の情報が得られます。

  • Bit 7. Negative flag
  • Bit 6. Overflow flag
  • Bit 5. Unused
  • Bit 4. Break flag
  • Bit 3. Decimal flag
  • Bit 2. Interrupt-disable flag
  • Bit 1. Carry flag
  • Bit 0. Zero flag

したがって、このステータスレジスタに対応するビットフィールドを使用して構造体を作成することができました。 これにより、レジスタ内の特定のビットを人が判読可能な名前で指定することができます。

overflowFlagフィールドの下のビットフィールドの固有の定義の1つに気付くでしょう。 これは、そのビットが未使用であり、コンパイラにその数のビットをスキップするよう指示することができるためです。 識別子名を使用しない場合は、識別子名を付けてください。

ビットフィールドの値にアクセスするには、ポインタの場合は、ドット(.)と矢印(->)演算子を使用して、他の構造フィールドと同様にアクセスできます。 実際には、ビットフィールドを取得するだけでなく、それらにも割り当てることができます。 彼らはそれを作るビット数まで整数リテラルを受け入れたり理解したりします。 例えば、3ビットのビットフィールドは最大7を計算することができ、4ビットのビットフィールドは最大15を計算することができる。

通常の構造要素とビットフィールドを混在させることは可能です。 私たちの構造の記事から、私たちの例を拡張します。 その記事では、私は従業員に関する様々な情報を保持しているemlpoyee構造を手直ししました。 彼らが現在働いているのか、中断しているのか、さらには時間従業員か給料であるのかを調べたいと思ったとします。 私はその情報を使って2つの完全な新しいバイトを取り、それぞれをcharに割り当てることができました。 しかし、ビットフィールドでは、私はこれらの2ビットの “フラグ”を1バイトに格納することができます:

注:ビットフィールドには制限があります。 それらは配列できず、ビットフィールドのアドレスを取得することはできません。 これは、アドレス指定可能な最小単位(バイト)よりも小さいためです。 さらに、フィールド上でプログラムが実行されているマシンに依存して、右から左または左から右に実行することができます。 したがって、ファイルに情報を書き込んだ場合、データが真に複製されると、別のマシンでその情報を読み取るかどうかはわかりません。 したがって、ビットフィールドを使用すると、プログラムの実行にマシン固有の依存関係が導入される可能性があります。

結論

前の記事で研究したように、構造は非常に便利ですが、町内で唯一の高度なデータ型ではありません。列挙型は、グローバル変数または定数の長いリストを指定することなく、整数値の識別子を指定することを可能にします。たとえば、この記事では、年のすべての月を列挙した列挙型を作成しました。私たちはまた、もう少し秘密ですが、とにかくuseulを対象にしました。時には、long intの配列に個々のcharバイトとしてアクセスする必要がある場合があります。最後に、ビットフィールドを切り上げました。特定のビットを名前で識別して処理できるCプログラミングの組み込み関数です。構造を含むこれらのデータ型すべてにおいて、ここで重要なのは、非常に特定のメモリを名前で識別する方法を設定することです。これらの配列の一部を特異な識別子の名前に短縮できなかった場合、私たちは同じ断片を何度も何度も何度も繰り返してきたので、何度も繰り返しています。

基本的なデータ型と高度なデータ型を使用することで、すべてのデータで何をすべきかを見極めることができます。その道の第一歩は、式を通って滞在することと、それを作る演算子です。算術演算子、ビット演算子、関係演算子、論理演算子、プログラム演算子について説明します(私が参照しています)。私はC言語で高度なデータ型の何かを照らすことができたらいいと思います。読んでくれてありがとう!

この記事はシリーズの一部です – どのようにプログラミングするには:Cプログラミング

この記事を読んでいただければ、パトリオンのサポートを検討することもできます。

しかし、毎月の約束が少しでもあれば、私はそれを得る、あなたは私にコーヒーを買うことを考えるかもしれない。

photo credit: Kyle McDonald small-enumeration via photopin (license)

あわせて読みたい

コメントを残す

%d人のブロガーが「いいね」をつけました。