信息系統建模中,第一步是信息的編碼,也就是說,信息如何在計算機中存儲。
為了硬件設計的簡單,通常使用芯片均采用二進制。並且,由於科技的局限性,數據的長度也是有限的。
比如,現在大多數電腦的數據總線是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
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進制指數