About#
To avoid misunderstandings, I rarely use statements like this
uint32_t *p;
p++;
p+=4;
but rather use this form
uint32_t *p;
uint32_t d;
d = p[4];
uint32_t *pt;
pt = &p[4];
However, in the case of traversal deduction, the latter form definitely requires a new variable for traversal. The former form can be based on passing pointers to functions, and O0 will definitely save more stack than the latter form.
Recently, to improve the performance of my library, I decided to sacrifice some readability and switch to less intuitive writing, hence the subsequent tests.
The conclusion is presented upfront, when the pointer + operation occurs, the type of the pointer being + determines how much RAM address is actually advanced, as intuitively shown in the table below.
Pointer Type | RAM Address Advancement |
---|---|
void* + 1 | 1 |
uint8_t* + 1 | 1 |
uint16_t* + 1 | 2 |
uint32_t* + 1 | 4 |
Other and struct pointers + 1 | Based on type size |
Address Value#
Use the following code for a simple test
#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};
/* Entry */
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;
}
Of course, it meets expectations. For example, for the pointer u32t, +3 accesses the third buffer value, which is very reasonable....... isn't it?
According to the well-known understanding of RAM, one address stores one byte, so u8t+1
advances by 1 byte while u32t+1
advances by 4 bytes, and the +1
operation produces different results.
Address Value#
To verify the above, the following code was used for a simple test
#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};
/* Entry */
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;
}
It can be seen that the advancement of values at the actual RAM addresses represented by the pointers is indeed different, even when using the same +1.
Is void*#
Many of our functions, as general tools, take void* as input. Depending on system status and flag conditions, they are treated as different pointers. Here is a test.
#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};
/* Entry */
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;
}
It can be seen that void* behaves completely consistently with actual RAM, +n is indeed +n.
Pretending Not to Be void*#
If void* is parsed as different type pointers, here is a test
#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};
/* Entry */
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;
}
It can be seen that, when the + operation occurs, the type being processed by + determines how much RAM address is actually advanced.
This article is synchronized and updated by Mix Space to xLog. The original link is https://www.yono233.cn/posts/shoot/24_7_27_C