程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 深入理解C語言-02-數據編碼

深入理解C語言-02-數據編碼

編輯:關於C語言

信息系統建模中,第一步是信息的編碼,也就是說,信息如何在計算機中存儲。

為了硬件設計的簡單,通常使用芯片均采用二進制。並且,由於科技的局限性,數據的長度也是有限的。

比如,現在大多數電腦的數據總線是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進制指數

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved