对于 volatile uint16_t *p_flash,p_flash + 1 会使地址增加2字节,而不是1字节。----来自deepseek的回答
·
1. 指针类型与地址计算
c
volatile uint16_t *p_flash = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR + offset);
地址计算规则:
-
USER_SYSTEM_DATA_ADDR + offset是字节地址 -
但
p_flash是uint16_t *类型指针 -
指针的算术运算与指针类型相关
2. 指针运算规则
c
// 示例代码演示 uint32_t base_addr = 0x0800F000; // 字节地址 // 情况1:字节指针 volatile uint8_t *p_byte = (volatile uint8_t *)base_addr; // p_byte + 1 → 地址加1字节 → 0x0800F001 // 情况2:半字指针(16位) volatile uint16_t *p_halfword = (volatile uint16_t *)base_addr; // p_halfword + 1 → 地址加2字节 → 0x0800F002 // 情况3:字指针(32位) volatile uint32_t *p_word = (volatile uint32_t *)base_addr; // p_word + 1 → 地址加4字节 → 0x0800F004
3. 您的具体情况分析
c
// 您的代码: p_flash = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR + offset); // 假设: // USER_SYSTEM_DATA_ADDR = 0x0800F000 // offset = 0 // 那么: p_flash + 0 → 指向地址 0x0800F000-0x0800F001 (2字节) p_flash + 1 → 指向地址 0x0800F002-0x0800F003 (2字节) p_flash + 2 → 指向地址 0x0800F004-0x0800F005 (2字节) // 访问数据: uint16_t data1 = p_flash[0]; // 读取 0x0800F000-0x0800F001 uint16_t data2 = p_flash[1]; // 读取 0x0800F002-0x0800F003
4. 实际使用示例
c
// 错误使用示例(常见错误)
void incorrect_usage(void) {
volatile uint16_t *p_flash = (volatile uint16_t *)USER_SYSTEM_DATA_ADDR;
// 错误:以为可以按字节递增
for(int i = 0; i < 10; i++) {
uint16_t data = p_flash[i]; // 实际是每2字节取一次
// 这不是按字节读取!
}
}
// 正确使用示例:按半字读取
void read_halfwords(void) {
volatile uint16_t *p_flash = (volatile uint16_t *)USER_SYSTEM_DATA_ADDR;
// 读取5个半字(10字节)
uint16_t buffer[5];
for(int i = 0; i < 5; i++) {
buffer[i] = p_flash[i]; // 每次读取2字节
}
}
// 正确使用示例:按字节读取(使用字节指针)
void read_bytes(void) {
volatile uint8_t *p_byte = (volatile uint8_t *)USER_SYSTEM_DATA_ADDR;
// 读取10个字节
uint8_t buffer[10];
for(int i = 0; i < 10; i++) {
buffer[i] = p_byte[i]; // 每次读取1字节
}
}
5. 与Flash编程函数结合
c
// 示例:将字节数组转换为半字数组进行Flash编程
flash_status_type write_with_halfword_ptr(uint32_t offset, uint8_t *data, uint32_t size) {
// 检查size是否为偶数(半字对齐)
if(size % 2 != 0) {
return FLASH_ALIGN_ERROR;
}
volatile uint16_t *p_flash = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR + offset);
uint16_t *p_data = (uint16_t *)data; // 将字节指针转换为半字指针
flash_unlock();
// 按半字数量编程
uint32_t halfword_count = size / 2;
for(uint32_t i = 0; i < halfword_count; i++) {
status = flash_halfword_program(
(uint32_t)&p_flash[i], // 注意:这里是计算地址
p_data[i]
);
if(status != FLASH_OPERATE_DONE) {
flash_lock();
return status;
}
while(flash_flag_get(FLASH_BUSY_FLAG) == SET);
}
flash_lock();
return FLASH_OPERATE_DONE;
}
6. 重要提醒:地址计算
c
// 正确获取绝对地址的方式
uint32_t get_actual_address(uint32_t offset) {
// 方法1:直接计算
uint32_t byte_addr = USER_SYSTEM_DATA_ADDR + offset;
// 方法2:通过指针转换(不推荐用于计算)
volatile uint16_t *p = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR);
uint32_t addr_from_ptr = (uint32_t)(p + offset); // 错误!这是加 offset*2
// 正确:如果要使用指针运算
uint32_t addr_correct = (uint32_t)(p + (offset / 2)); // 需要除以2
return byte_addr; // 使用方法1最简单
}
7. 实际应用建议
c
// 建议:使用明确的函数进行不同精度的访问
uint8_t flash_read_byte(uint32_t offset) {
volatile uint8_t *p = (volatile uint8_t *)(USER_SYSTEM_DATA_ADDR);
return p[offset];
}
uint16_t flash_read_halfword(uint32_t offset) {
// 确保offset是2的倍数
if(offset % 2 != 0) {
return 0xFFFF; // 错误值
}
volatile uint16_t *p = (volatile uint16_t *)(USER_SYSTEM_DATA_ADDR);
uint32_t halfword_index = offset / 2;
return p[halfword_index];
}
uint32_t flash_read_word(uint32_t offset) {
// 确保offset是4的倍数
if(offset % 4 != 0) {
return 0xFFFFFFFF; // 错误值
}
volatile uint32_t *p = (volatile uint32_t *)(USER_SYSTEM_DATA_ADDR);
uint32_t word_index = offset / 4;
return p[word_index];
}
总结回答您的直接问题:
是的,对于 volatile uint16_t *p_flash,p_flash + 1 会使地址增加2字节,而不是1字节。
这是因为:
-
C语言的指针运算会自动考虑类型大小
-
uint16_t类型占用2字节 -
指针加1实际上是指向下一个同类型元素,而不是下一个字节
如果您需要按字节递增访问,应该使用 uint8_t * 类型的指针
更多推荐




所有评论(0)