深入理解C语言-02-数据编码

信息系统建模中,第一步是信息的编码,也就是说,信息如何在计算机中存储。

为了硬件设计的简单,通常使用芯片均采用二进制。并且,由于科技的局限性,数据的长度也是有限的。

比如,现在大多数电脑的数据总线是32位/或者64位。以32位系统为例,能编码的集合大小为 2的32次方,也就是4294967296。


显然这是一个有限集合。而现实中的模拟信息通常是无限集合。

这就涉及到信息的编码,即建立一个映射函数: f(信息)=计算机中的信息编码。


信息的编码设计涉及到数据的大小选择,实际项目中一般是考虑当前需求和后期的扩展选择一个折中值。


对于C语言来说,主要考虑以下3个方面:

数据类型的大小

数据的字节序

数据的对齐


数据类型大小的差异是C语言可移植性方面的大问题。


为此,在新系统使用前,需要参考芯片手册(DataSheet)或写如下代码进行测试。

printf("char[%d] short[%d] int[%d] long[%d] long long[%d] float[%d] double[%d] \n",
sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(long long), 
sizeof(float), sizeof(double));


在32位系统,一般返回以下结果:

char[1] short[2] int[4] long[4] long long[8] float[4] double[8]


数据的字节序

通常,x86架构采用的是小端表示(Little-Endian), MIPS架构采用的是大端表示(BigEndian)。

比如0x12345678 在x86中是 按照 0x78 0x56 0x34 0x12 的顺序依次存储,

而在MIPS架构中则通常是按照 0x12 0x34 0x56 0x78   的顺序依次存储。

可以写以下代码来测试大小端:

int checkEndian()
{
int x = 0x12345678;
if (*(char*)(&x) == 0x78) {
printf("Little Endian\n");
return 0;
} else {
printf("Big-Endian");
return 1;
}
}


数据的对齐:

为什么要考虑对齐? 一方面是为了性能考虑,另一方面则是芯片设计上的限制。

比如公司使用的MIPS芯片要求数据地址必须4字节对齐,否则就会总线错误(Bus Error)


当然,按照时间空间的矛盾性,对齐必然会导致内存的浪费。这样在E2ROM使用上来说,也就意味着硬件成本的上升。


如何节约? 一种办法是牺牲时间,进行数据压缩。还有一种更方便的办法就是自己控制对齐。

当然,最好的设计就是从整体上考虑对齐,合理安排数据的位置。


控制对齐的方式与编译器有关系,通常:

gcc采用

__attribute__ ((aligned (n))

vc采用:

#pragma pack(n)


可以写如下代码进行测试:

VC:

typedef struct  stTest1 
{
char ch;
int x;
short y;
} Test1;


#pragma pack(1)
typedef struct  stTest2
{
char ch;
int x;
short y;
} Test2;
#pragma pack(4)


gcc:

typedef struct  stTest1 
{
char ch;
int x;
short y;
} Test1;


typedef struct  stTest2
{
char ch;
int x;
short y;
} Test2 __attribute__ ((aligned (1));


Log代码:

printf("sizeof(Test1)= %d, sizeof(Test2) = %d \n", sizeof(Test1), sizeof(Test2));
printf("__alignof(Test1)= %d, __alignof(Test2) = %d \n", __alignof(Test1), __alignof(Test2));


输出:

sizeof(Test1)= 12, sizeof(Test2) = 7
alignof(Test1)= 4, __alignof(Test2) = 1


接下来就是数据的表示。

通常我们有以下方式:

1> 利用bit位,设计每一个数据的存储位置与大小。

比如一副扑克牌,有4种花色,每一种花色有13种取值,这样我们便可以按如下方式编码:

1个字节有8个Bit位, 0-3 4个Bit 表示A-K, 4-5 2个Bit表示花色,大小王特殊编码。

8个Bit    7    6     5       4       3      2      1  0

                                                |                    |

                                                —— ————     ->  0001 -> A,  0001-> 2, ..., 1101 -> K 

                             |         |

                             ——     ->  00 -> 红桃 01-> 黑桃  02-> 黑梅 03 -> 红方

大王:       000000

小王:       111111


2> 利用C语言提供的基本数据类型(char, short, int, unsign int, float, double),并配合数组与结构体来构建复杂数据结构。

    对于,非线性结构,还需要指针来配合。

在使用基本类型前,按照C语言的设计哲学(谁使用谁负责理念),必须搞懂以下几点:

1> 各种格式的表示范围

2> 数据的二进制值是什么

3> 是否有精度丢失或数据溢出?如何判断?


2.1 表示范围

以无符号整数为例,在32位系统下:

unsigned char     8位    表示范围   0~255  

unsigned short    16位    表示范围   0~65535

unsigned long   32位    表示范围   0~4294967295

unsigned long long   64位    表示范围   0~18446744073709551615

 

这些值并不需要记忆精确值,只需要大致了解级数就可以了。

具体值我们可以通过下面代码来了解:

#include<limits.h>

int testLimit()
{
printf("min of char: %d \n", SCHAR_MIN);
printf("max of char: %d \n", SCHAR_MAX);
printf("min of short: %d \n", SHRT_MIN);
printf("max of short: %d \n", SHRT_MAX);
printf("min of int: %d \n", INT_MIN);
printf("max of int: %d \n", INT_MAX);
printf("min of long: %d \n", LONG_MIN);
printf("max of long: %d \n", LONG_MAX);
printf("min of long long: %llu \n", LLONG_MIN);
printf("max of long  long: %llu \n", LLONG_MAX);


printf("max of unsigned char: %d \n", UCHAR_MAX);
printf("max of unsigned short: %d \n", USHRT_MAX);
printf("max of unsigned int: %u \n", UINT_MAX);
printf("max of unsigned long: %u \n", ULONG_MAX);
printf("max of unsigned long long: %llu \n", ULLONG_MAX);
return 0;
}

在32位系统上输出:

min of char: -128
max of char: 127
min of short: -32768
max of short: 32767
min of int: -2147483648
max of int: 2147483647
min of long: -2147483648
max of long: 2147483647
min of long long: 9223372036854775808
max of long long: 9223372036854775807
max of unsigned char: 255
max of unsigned short: 65535
max of unsigned int: 4294967295
max of unsigned long: 4294967295
max of unsigned long long: 18446744073709551615

关于浮点数请参考float.h头文件。以下翻译来自百度文库:

double:


 DBL_DIG double小数点后面精确的位数 
 DBL_EPSILON  最小的尾数 (1.0+DBL_EPSILON != 1.0)

 DBL_MANT_DIG 尾数中的位数 
 DBL_MAX 最大值  

 DBL_MAX_10_EXP 最大10进制指数 
 DBL_MAX_EXP 最大2进制指数 

 DBL_MIN 最小值  

 DBL_MIN_10_EXP 最小10进制指数
 DBL_MIN_EXP 最小2进制指数 


float :

  FLT_DIG float小数点后面精确的位数
  FLT_EPSILON 最小的尾数 (1.0+FLT_EPSILON != 1.0)

  FLT_MANT_DLG 尾数中的位数 
  FLT_MAX 最大值  

  FLT_MAX_10_EXP 最大10进制指数 

FLT_MAX_EXP 最大2进制指数 
FLT_MIN 最小值  

FLT_MIN_10_EXP 最小10进制指数 
FLT_MIN_EXP 最小2进制指数
 
FLT_RADIX 进制基数 FLT_ROUNDS 加法舍入 

long double:

  LDBL_DIG long double小数点后面精确的位数 
  LDBL_EPSILON 最小的尾数 (1.0+LDBL_EPSILON != 1.0)
  LDBL_MANT_DLG 尾数中的位数 

 LDBL_MAX 最大值 
 LDBL_MAX_10_EXP 最大10进制指数 

 LDBL_MAX_EXP 最大2进制指数 

 LDBL_MIN 最小值  

 LDBL_MIN_10_EXP 最小10进制指数 

 LDBL_MIN_EXP 最小2进制指数  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简介: C语言是编程语言中的一朵奇葩,虽已垂垂老矣,但却屹立不倒,诞生了数十年,仍然是最流行的编程语言之一。C语言看似简单,却不易吃透,想要运用好,更是需要积淀。本书是一本修炼C程序设计能力的进阶之作,它没有系统地去讲解C语言的语法和编程方法,而是只对C语言中不容易被初学者理解的重点、难点和疑点进行了细致而深入的解读,揭露了C语言中那些鲜为普通开发者所知的秘密,旨在让读者真正掌握C语言,从而编写出更高质量的C程序代码。 全书一共11章:第1章重点阐述了C语言中不易被理解的多个核心概念,很多初学者在理解这些概念时都会存在误区;第2~8章对预处理、选择结构和循环结构的程序设计、数组、指针、数据结构、函数和文件等知识点的核心问题和注意事项进行了讲解;第9章介绍了调试和异常处理的方法及注意事项;第10章对C语言中的若干容易让开发者误解误用的陷阱知识点进行了剖析;第11章则对所有程序员必须掌握的几种算法进行了详细的讲解;附录经验性地总结了如何养成良好的编码习惯,这对所有开发者都尤为重要。 本书主要内容:  堆和栈、全局变量和局部变量、生存期和作用域、内部函数和外部函数、指针变量、指针数组和数组指针、指针函数和函数指针、传址和传值、递归和嵌套、结构体和共用体、枚举、位域等较难理解的核心概念的阐述和对比;  预处理中的疑难知识点,包括文件的包含方式、宏定义及其常见错误解析、条件编译指令和#pragma指令的使用等;  if、switch等选择结构语句的使用注意事项和易错点解析;  for、while、do while等循环结构语句的使用注意事项和易错点解析;  循环结构中break、continue、goto、return、exit的区别;  一维数组、二维数组、多维数组、字符数组、动态数组的定义和引用,以及操作数组时的各种常见错误解析;  不同类型的指针之间的区别,以及指针的一般用法和注意事项;  指针与地址、数组、字符串、函数之间的关系,以及指针与指针之间的关系;  枚举类型的使用及注意事项,结构体变量和共用体变量的初始化方法及引用;  传统链表的实现方法和注意事项,以及对传统链表实现方法的颠覆;  与函数参数、变参函数、函数调用、函数指针相关的一些难理解和容易被理解错的知识点解析;  文件和指针的使用原则、技巧和注意事项;  函数调用和异常处理的注意事项和最佳实践;  与strlen、sizeof、const、volatile、void、void*、#define、typedef、realloc、malloc、calloc等相关的一些陷阱知识点的解析;  时间复杂度、冒泡排序法、选择排序法、快速排序法、归并排序法、顺序排序法、二分查找等常用算法的详细讲解;  良好的编码习惯和编程风格。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值