信息系统建模中,第一步是信息的编码,也就是说,信息如何在计算机中存储。
为了硬件设计的简单,通常使用芯片均采用二进制。并且,由于科技的局限性,数据的长度也是有限的。
比如,现在大多数电脑的数据总线是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进制指数