Cでアドレスを計算する方法を学習しようとしています。以下のコードでは、32ビットのリトルエンディアンマシンでコンパイルされていると想定しています。
struct {
int n;
char c;
} A[10][10];
A [0] [0]のアドレスが1000(10進数)であるとすると、A [3] [7]のアドレスは何になりますか?どんな助けでも大歓迎です!
Cでアドレスを計算する方法を学習しようとしています。以下のコードでは、32ビットのリトルエンディアンマシンでコンパイルされていると想定しています。
struct {
int n;
char c;
} A[10][10];
A [0] [0]のアドレスが1000(10進数)であるとすると、A [3] [7]のアドレスは何になりますか?どんな助けでも大歓迎です!
Cは行優先順です。つまり、一番左のインデックスが最初に計算されます。したがって:
&A[3] == 1000 + (3 * 10 * sizeof(your_struct))
列を見つけるには、残りのインデックスを追加するだけです。
&A[3][7] == 1000 + (3 * 10 * sizeof(your_struct)) + (7 * sizeof(your_struct))
これは、ビッグエンディアンとリトルエンディアンのアーキテクチャとは関係がないことに注意してください。これは単語内のバイトの場所にすぎませんが、配列内の構造体の場所が必要です。
また、コンパイラが構造体を埋め込む可能性があるため、sizeof(your_struct)
保証されていません。sizeof(n) + sizeof(c)
最後に、マシンの32 ビットの性質は、メモリ アドレス レジスタのサイズが 32 ビットであることを意味します。(または別の言い方をすれば、sizeof(void*)==32
)。これは、プロセッサが実際にアドレスを割り当てることができるメモリの量を示しています。これは、C のデータ型のサイズとは別の問題です。
これは、C 言語の標準に依存するのではなく、コンパイラ、コンパイラのバージョン、および使用/ターゲットにしている OS に依存します。
特定のケースの結果を得る唯一の方法は、手動でテストすることです。
これは確かにコンパイラとシステムに依存します。しかし、推測する必要はありません。コンパイルして試すだけです
#include <stdio.h>
int main()
{
struct {
int n;
char c;
} A[10][10];
printf("%08x\n", &A[0][0]);
printf("%08x\n", &A[0][1]);
printf("%08x\n", &A[1][0]);
...
printf("%08x\n", &A[3][7]);
...
}
配列表記は、次のように、要素のアドレスを計算して逆参照するための簡単な方法です。
int a[5][15];
Address of a[3][7]: &a + 3 * 15 * sizeof(int) + 7 * sizeof(int)
これが、最後の次元以外のすべてを知らずに n 次元配列を使用できない理由です。コンパイラは、アドレスを計算するために追加するオフセットを認識しません。
この場合、構造体を使用しているという事実によって問題が複雑になります。アラインメントの問題があり、構造体はコンパイラによってパディングされ、ワード境界にアラインされます。この場合、構造体自体は 5 バイトを使用し、次のワード境界は 8 バイトになるため、コンパイラは、違いを補うために構造体に未使用の 3 バイトを追加する可能性があります。(そうすることでパフォーマンス上の利点があります。) もちろん、これはまったく保証されていません。コンパイラがそのような状況を処理する方法を手動で指定できます。
注:他の人が述べているように、これはシステムとコンパイラに大きく依存しているため、これを福音と見なさないでください。自分の場合に結果がどうなるかを完全に確認するために、自分で試してください.
言語ではなく、システムに完全に依存しています。
また、すべての 2-D、3-D などの配列は実際には順次割り当てられます。メモリは順次(0X00000000 to 0xFFFFFFFF)
であるため、そのような 2-D メモリなどはありません。
row
メジャーかcolumn
メジャーかにかかわらず、メモリがどのように割り当てられるかはシステムに完全に依存しています
行メジャーの式:
&A[3][7] == &A[0][0] + (3 * 10 * sizeof(struct s)) + (7 * sizeof(struct s))
列メジャーの場合:
&A[3][7] == &A[0][0] + (7 * 10 * sizeof(struct s)) + (3 * sizeof(struct s))
また、コンパイラは、構造パディングによって最適化し、CPU によるアクセスを高速化します。
そのため、構造体サイズの 1 つのオブジェクトの場合は (int のサイズが 4 バイトの場合)8
ではなく5