嵌入式知识点总结 ARM体系与架构 专题提升(四)-编程
针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。
目录
1.嵌人式编程中,什么是大端?什么是小端 ?
在嵌入式编程中,大端和小端是字节序(Byte Order)的概念,用于描述多字节数据在内存中的存储方式。
大端存储是指将数据的高字节存储在低地址,低字节存储在高地址的一种方式。
假设有一个32位整数 0x12345678
,在内存中的存储方式如下(地址从小到大):
地址 | 数据(字节值) |
---|---|
0x00 | 0x12 |
0x01 | 0x34 |
0x02 | 0x56 |
0x03 | 0x78 |
特点:数据从高字节到低字节依次存储。
小端存储是指将数据的低字节存储在低地址,高字节存储在高地址的一种方式。
同样的32位整数 0x12345678
,在内存中的存储方式如下(地址从小到大):
地址 | 数据(字节值) |
---|---|
0x00 | 0x78 |
0x01 | 0x56 |
0x02 | 0x34 |
0x03 | 0x12 |
特点:数据从低字节到高字节依次存储。
大端:
通常用于网络传输(网络字节序)。
更符合人类阅读习惯(从高位到低位)。
小端:
大多数嵌入式设备和PC(如Intel、ARM)采用小端存储。
存储和访问数据时效率更高(低地址直接存储低字节)。
2.如何判断计算机处理器是大端,还是小端 ?
#include <stdio.h>
int main() {
unsigned int x = 0x12345678; // 一个32位整数
unsigned char *ptr = (unsigned char *)&x; // 取x的地址并转为字节指针
if (*ptr == 0x78) {
printf("Little-Endian (小端模式)\n");
} else if (*ptr == 0x12) {
printf("Big-Endian (大端模式)\n");
} else {
printf("Unknown Byte Order\n");
}
return 0;
}
如果输出Little-Endian (小端模式)
,说明低字节存储在低地址(小端)。
如果输出Big-Endian (大端模式)
,说明高字节存储在低地址(大端)。
补充:*ptr存的起始地址嘛
3.如何进行大小端的转换 ?
大小端的转换是指在内存中交换数据的字节顺序,将大端存储格式转换为小端存储格式,或反之。这通常用于跨平台数据通信、存储格式兼容性处理等场景。
通过按位操作手动调整字节顺序。
#include <stdio.h>
unsigned int swap_endian(unsigned int x) {
return ((x & 0xFF000000) >> 24) | // 高8位 -> 低8位
((x & 0x00FF0000) >> 8) | // 次高8位 -> 次低8位
((x & 0x0000FF00) << 8) | // 次低8位 -> 次高8位
((x & 0x000000FF) << 24); // 低8位 -> 高8位
}
int main() {
unsigned int x = 0x12345678;
unsigned int y = swap_endian(x);
printf("Original: 0x%x\n", x);
printf("Converted: 0x%x\n", y);
return 0;
}
Original: 0x12345678
Converted: 0x78563412
4.如何对绝对地址0x100000赋值?
通过将绝对地址类型转换为指针并进行解引用,可以对该地址赋值。
#include <stdio.h>
int main() {
unsigned int *addr = (unsigned int *)0x100000; // 将绝对地址0x100000转为指针
*addr = 0x12345678; // 向地址写入值
printf("Value at 0x100000: 0x%x\n", *addr); // 打印地址中的值
return 0;
}
地址合法性:
需要确保 0x100000
是有效的内存地址。
该地址可能位于特定设备寄存器区域(如外设地址)或已映射的内存区域。
使用无效地址会导致段错误 (Segmentation Fault) 或异常。
访问权限:
确保程序有权访问该地址,某些地址可能需要特定的权限(如特权模式下的访问)。
编译器优化:
某些编译器可能会优化掉对特定地址的操作。如果是硬件相关的地址访问,建议将指针声明为 volatile
,以防止编译器优化。
volatile unsigned int *addr = (unsigned int *)0x100000;
操作系统影响:
在裸机(无操作系统)开发环境中,直接访问绝对地址通常是可行的。
在操作系统(如 Linux)中,用户态程序无法直接访问绝对物理地址,需通过内核驱动或内存映射接口(如 mmap
)实现。
如果是在 Linux 用户态下操作绝对地址,可以使用 mmap
进行内存映射。
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#define PHYS_ADDR 0x100000 // 物理地址
#define MAP_SIZE 0x1000 // 映射大小
int main() {
int fd = open("/dev/mem", O_RDWR | O_SYNC); // 打开物理内存设备
if (fd < 0) {
perror("open /dev/mem failed");
return -1;
}
void *mapped_addr = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PHYS_ADDR);
if (mapped_addr == MAP_FAILED) {
perror("mmap failed");
close(fd);
return -1;
}
volatile unsigned int *addr = (unsigned int *)mapped_addr;
*addr = 0x12345678; // 写入值
printf("Value at 0x100000: 0x%x\n", *addr);
munmap(mapped_addr, MAP_SIZE); // 解除映射
close(fd);
return 0;
}
在裸机开发中,直接使用指针操作即可对绝对地址赋值。
在操作系统中,需要通过内核支持(如 /dev/mem
和 mmap
)访问物理地址。
对硬件地址操作时,请确保地址的合法性和访问权限,并根据需要使用 volatile
关键字防止优化。
原文地址:https://blog.csdn.net/weixin_64593595/article/details/145301224
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!