について#
誤解を避けるために、私はこのような文をあまり使用しません
uint32_t *p;
p++;
p+=4;
代わりに、このような形式だけを使用します
uint32_t *p;
uint32_t d;
d = p[4];
uint32_t *pt;
pt = &p[4];
しかし、推論を行う際には、後者の形式には新しい変数が必要です。
前者の形式は関数の引数としてポインタを渡すことができ、O0 では必ず後者の形式よりもスタックを節約します。
最近、ライブラリのパフォーマンスを向上させるために、可読性を犠牲にして直感的でない書き方に変更したため、後続のテストが行われます。
結論を先に述べます。ポインタ + この操作が発生したとき、+ で処理されるポインタの型が実際にどれだけ RAM アドレスを進めるかを決定します。直感的には以下の表をご覧ください。
ポインタの型 | RAM アドレスの進行量 |
---|---|
void* + 1 | 1 |
uint8_t* + 1 | 1 |
uint16_t* + 1 | 2 |
uint32_t* + 1 | 4 |
その他および構造体ポインタ + 1 | 型のサイズに依存 |
アドレスの数値#
以下のコードを使用して簡単なテストを行います
#include <stdio.h>
#include <stdint.h>
#include <string.h>
uint8_t u8t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
uint16_t u16t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
uint32_t u32t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
/* エントリ */
int main(int argc, char *argv[])
{
uint8_t p8get;
uint16_t p16get;
uint32_t p32get;
p8get = u8t[1]; // = 1
p8get = *(uint8_t *)(u8t + 1); // = 1
p8get = u8t[2]; // = 2
p8get = *(uint8_t *)(u8t + 2); // = 2
p8get = u8t[3]; // = 3
p8get = *(uint8_t *)(u8t + 3); // = 3
p16get = u16t[1]; // = 1
p16get = *(uint16_t *)(u16t + 1); // = 1
p16get = u16t[2]; // = 2
p16get = *(uint16_t *)(u16t + 2); // = 2
p16get = u16t[3]; // = 3
p16get = *(uint16_t *)(u16t + 3); // = 3
p32get = u32t[1]; // = 1
p32get = *(uint32_t *)(u32t + 1); // = 1
p32get = u32t[2]; // = 2
p32get = *(uint32_t *)(u32t + 2); // = 2
p32get = u32t[3]; // = 3
p32get = *(uint32_t *)(u32t + 3); // = 3
return 0;
}
もちろん、非常に期待通りです。例えばポインタ u32t、+3 は第三のバッファ値にアクセスすることになります。非常に合理的です.......でしょうか?
広く知られている RAM の理解に基づくと、1 つのアドレスは 1 バイトを格納します。したがって、u8t+1
は 1 バイト進み、u32t+1
は 4 バイト進むため、+1
という操作は異なる結果を生み出します。
アドレスの数値#
上記を検証するために、以下のコードを使用して簡単なテストを行います
#include <stdio.h>
#include <stdint.h>
#include <string.h>
uint8_t u8t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
uint16_t u16t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
uint32_t u32t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
/* エントリ */
int main(int argc, char *argv[])
{
uint8_t *p8get;
uint16_t *p16get;
uint32_t *p32get;
p8get = u8t; // = 0x7FF6757b4000 <u8t>
p16get = u16t; // = 0x7FF6757b4010 <u16t>
p32get = u32t; // = 0x7FF6757b4040 <u32t>
p8get = u8t + 1; // = 0x7FF6757b4001 <u8t+1>
p16get = u16t + 1; // = 0x7FF6757b4012 <u16t+2>
p32get = u32t + 1; // = 0x7FF6757b4044 <u32t+4>
p8get = u8t + 2; // = 0x7FF6757b4002 <u8t+2>
p16get = u16t + 2; // = 0x7FF6757b4014 <u16t+4>
p32get = u32t + 2; // = 0x7FF6757b4048 <u32t+8>
return 0;
}
ポインタが表す実際の RAM アドレスにおいて、その数値の進行は確かに異なります。同じ +1 を使用していてもです。
void* とは#
私たちの多くの関数は、汎用ツールとして void* を受け取ります。システムの状態やフラグ条件に応じて、異なるポインタとして判断されます。以下のようなテストがあります。
#include <stdio.h>
#include <stdint.h>
#include <string.h>
uint8_t u8t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
uint16_t u16t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
uint32_t u32t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
/* エントリ */
int main(int argc, char *argv[])
{
void *pVget;
uint64_t pVV;
pVget = (void *)u8t; // = 0x7FF61F184000 <u8t>
pVget++;
pVV = (uint64_t)pVget; // = 0x7FF61F184001 <u8t+1>
pVget = (void *)u16t; // = 0x7FF61F184010 <u16t>
pVget++;
pVV = (uint64_t)pVget; // = 0x7FF61F184011 <u16t+1>
pVget = (void *)u32t; // = 0x7FF61F184040 <u32t>
pVget++;
pVV = (uint64_t)pVget; // 0x7FF61F184041 <u32t+1>
return 0;
}
void* の実際の RAM に対する動作モードは完全に一致しており、+n は + n です。
偽の void*#
void* を異なる型のポインタとして解析すると、以下のようなテストがあります。
#include <stdio.h>
#include <stdint.h>
#include <string.h>
uint8_t u8t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
uint16_t u16t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
uint32_t u32t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
/* エントリ */
int main(int argc, char *argv[])
{
void *pVget;
pVget = u8t; // = 0x7FF69FF64000 <u8t>
pVget = (uint8_t *)pVget + 1; // = 0x7FF69FF64001 <u8t+1>
pVget = u8t; // = 0x7FF69FF64000 <u8t>
pVget = (uint8_t *)(pVget + 1); // = 0x7FF69FF64001 <u8t+1>
pVget = u16t; // = 0x7FF69FF64010 <u16t>
pVget = (uint16_t *)pVget + 1; // = 0x7FF69FF64012 <u16t+2>
pVget = u16t; // = 0x7FF69FF64010 <u16t>
pVget = (uint16_t *)(pVget + 1); // = 0x7FF69FF64011 <u16t+1>
pVget = u32t; // 0x7FF69FF64040 <u32t>
pVget = (uint32_t *)pVget + 1; // 0x7FF69FF64044 <u32t+4>
pVget = u32t; // 0x7FF69FF64040 <u32t>
pVget = (uint32_t *)(pVget + 1); // 0x7FF69FF64041 <u32t+1>
return 0;
}
+ という操作が発生したとき、+ で処理される型が実際にどれだけ RAM アドレスを進めるかを決定します。
この記事は Mix Space によって xLog に同期更新されました
元のリンクは https://www.yono233.cn/posts/shoot/24_7_27_C