C语言嵌入式--数据存储与指针笔记6

(一)程序优化思路

  • 算法:减少指令数,提高运行效率
  • 缓存:改变数据的存储方式、读写速度

(二)存储的基本概念

  • 存储单元
存储单元 描述
计算机存储的最小单位
字节 计算机常用的存储单位
开发者常用

思考1:一个字一定占4个字节吗?

不一定。由所使用的编译器决定,编译器的分配策略又是由cpu架构决定,cpu架构最终由指令集决定(采用的指令集决定了cpu架构的设计)

  • 存储模式
存储模式 描述
大端模式 高地址存储低字节数据 低地址存储高字节数据
小端模式 高地址存储高字节数据 低地址存储低字节数据

思考2:什么是位序和字节序?

位序:一个字节里的各个位的存放顺序
字节序:两个或者两个以上字节数据中,一个字节的存放顺序

  • 如何判断大端模式与小端模式(32位机)
    方法1(常规):
int  val = 0x11223344;
char tmp;

tmp = val;

if (val == 0x11)
{
    printf("Big Endian.\n\r");
}
else
{
    printf("Little Endian.\n\r");
}

方法2(联合):

union value { //所有变量共享内存
    int  a;
    char b;
}val;

val.a = 0x11223344;
if (val.a == 0x11)
{
    printf("Big Endian.\n\r");
}
else
{
    printf("Little Endian.\n\r");
}

思考2:为什么会有大小端之分?

1 小端符合人的思维习惯
2 大端符合计算机运算逻辑。不需要考虑对应关系,按照字节把数据从左往右、由低到高的字节序进行读写
3 大端一般用在网络字节序和各种编解码中

PS:嵌入式处理器的寄存器:MSB、LSB

  • 数据的大小端转换(32位机)
#define swap_endian_u32(value) { \
    (((value) & 0xff000000 >> 24) | ((value) & 0x00ff0000 >> 8)  \
    |((value) & 0x0000ff00 << 8) | ((value) & 0x000000ff << 24)) \
} 

int main(void)
{
    int v = 0x11223344;
    //int value = swap_endian_u32(v) ;
    int value = (((x) & 0xff) << 24) + (((x >> 8) & 0xff)<<16) + 
                (((x >> 16) & 0xff) << 8) + (((x >> 24) & 0xff));
    printf("value = 0x%x\n", value);

    return 0;
 } 

(三)有符号数与无符号数

  • 原码、反码和补码

    1 计算机采用补码存储数据
    2 无符号数的存储:原码、反码和补码相同
    3 有符号数的存储:

    a 有符号数采用补码的形式存储
    b 有符号数反码:最高位保持不变,其它位按位取反
    c 有符号数补码:反码+1


•示例:+0
•原码:0000 0000
•示例:-0
•原码:1000 0000
•反码:1111 1111
•补码:10000 0000
  • 计算机为什么要使用补码来存储数据?
    1 解决0的编码问题
    2 减法运算可以转换为加法,省去硬件的减法电路。CPU只要有全加器、求补电路即可
    3 符号位也能参与运算,和其它位统一处理。有补码表示的数相加,最高位有进位时,则进位被舍弃

(四)数据溢出

无符号数的溢出:取模运算,继续“轮回”

unsigned char c = 255;
printf("c = %u\n",c);
c++;
printf("C = %u\n",c);

有符号数的溢出:

不会触发异常:C语言的宽松性、不作类型安全性检查
会产生未定义行为

signed char c2 = 127;
printf("c2 = %d\n",c2);
c2++;
printf("c2 = %d\n",c2);//由编译器决定. gcc编译器对有符号数的数据溢出也是“轮回”
  • 如何防范整数溢出?
    有符号数相加:两个正数相加小于0; 两个负数相加大于0
char a = 125;
char b = 30;
if((unsigned char)a+(unsigned char)b > SCHAR_MAX)
    printf("data overflow!\n");
char c = a + b;
printf("%d\n",c);

无符号数相加:两个数相加,和小于其中任何一个加数

unsigned char a = 255;
unsigned char b = 40;
unsigned char c;
c = a + b;
if(c < a || c < b)
    printf("data overflow!\n");
printf("c = %u\n",c);

(五)数据对齐

数据对齐原则:基本类型数据成员按自然边界对齐
为什么要数据对齐?–>CPU硬件限制

不同硬件平台对存储空间的管理不同
为了简化CPU硬件设计,简化了地址访问
编译器会根据硬件平台选择合适的对齐方式

  • 结构体对齐原则?
    •结构体内各成员按各自自然对齐方式
    •结构体整体对齐方式:按最大成员对齐或其整数倍
  • 联合体对齐原则
    •按最大成员大小分配空间
    •联合体的对齐:各成员对齐字节数的最小公倍数

  • 显示指定对齐方式(两种方法)
    这里写图片描述

(六)数据类型转换

  • 为什么要类型转换
    1 计算机CPU执行运算时的硬件要求
    2 类型、大小、存储方式要相同
  • 转换方式
    1 隐式类型转换
    2 强制类型转换
  • 隐式类型转换
    •算术、逻辑、赋值表达式中数据类型不同
    •函数形参与实参类型不匹配
    •函数返回值类型与函数类型不匹配
  • 隐式类型转换
    •低精度->高精度 有符号->无符号
    •signed->unsigned
    •char -> short -> int -> unsigned -> long -> double -> long double
    •char -> short ->int ->long ->long long ->float ->double ->…
  • 强制类型转换
    •char—int:值不变、存储格式发生变化
    •int—char:截断
    •signed—unsigned:值改变,存储格式不发生变化

猜你喜欢

转载自blog.csdn.net/skyleemon/article/details/80161392