1. 程式人生 > >頂級c程式設計師之路 選學篇-1 深入理解位元組,位元組序與位元組對齊

頂級c程式設計師之路 選學篇-1 深入理解位元組,位元組序與位元組對齊

                         深入理解位元組,位元組序與位元組對齊

一 總述

   作為一個職業的coder玩家,首先應該對計算機的位元組有所瞭解。

   我們經常談到的2進位制流,位元組(字元)流,資料型別流(針對程式設計),結構流等說法,2進位制流,01的操作,屬於cpu級。從字元流向上都是我們玩家關心,位元組流屬於作業系統級。今天談的就是位元組流操作。

二 位元組

   因為計算機用二進位制,所以希望基本儲存單位的是2的n次方(應該和硬體有關)。  這樣讀取位元組的時候,開銷不會太高,可以達到最大效能,因為剛開始,計算機是美國發明的,西文字元(英文字母大小寫,數字,其他特殊字元等將近有1百多個,所以用

7位來表示,這樣可以把所有西文字元表達完,再加上一位校檢位,一共8位,由於ASCⅡ的廣泛應用,所有後來,一個位元組佔8位就成了國際規定的標準了,一直沿用至今(有待研究,但不是今天的主題)。

   一個位元組佔8個2進位制位,資料型別流,就是在c語言裡面的資料型別佔多少個位元組。然後直接操作資料型別。在目前的32位系統中,c語言的基本資料型別有以下幾種:

Char  佔一個位元組 (-2^7 - 2^7-1 ,-128 到 127)最高位 為符號位

Unsigned char 佔一個位元組   (0-2^8,0到255)

Short   佔2個位元組 (-2^15 - 2^15-1 , -32768到32767)最高位 為符號位

Unsigned short 佔2個位元組 (0 - 2^16 , 0到65536)

Int (字長,對於32位機為32位,16位機為16位,長度不固定,和系統平臺有關,處理器位數有關,代表定址空間),在32位機佔4個位元組(-2^31-2^31 )最高位 為符號位

Unsigned  int 佔4個位元組(0-2^32 )

Long int 為4個位元組,在16,32位機都佔4個位元組(-2^31-2^31 )最高位 為符號位

Unsigned  long int佔4個位元組(0-2^32 )

sizeof(short) <= sizeof(int) <= sizeof(long)  

在32位機 int和long都是32位,沒有什麼大的區別,但還是有些小的區別,有時最好用long,他大小固定,如果到其他平臺,比如64位,他還是佔4個位元組,而int卻佔8個位元組,可以增加程式碼的可移植性。

Long long int 佔8個位元組(c99標準)  

Unsigned long long int 佔8個位元組(c99標準)  

浮點型別 由於浮點型別和整形的編碼不一樣,所以浮點型需要特殊分析。

Float 佔4個位元組  

Double 佔8個位元組 

深入理解浮點型別,請看這邊文章:

主要是這不是這篇文章的重點。

進入今天的主題

三 位元組序

  為什麼有位元組序這個概念存在呢?

不同的CPU有不同的位元組序型別 這些位元組序是指整數在記憶體中儲存的順序 這個叫做主機序 ,就是多個位元組在記憶體中擺放位置順序和解釋順序。
最常見的有兩種 :

1. Little endian:將低序位元組儲存在起始地址 4321


2. Big endian:將高序位元組儲存在起始地址    1234
以前還有什麼Middle endian,就亂序,也被淘汰。


LE little-endian 
最符合人的思維的位元組序 
地址低位儲存值的低位 
地址高位儲存值的高位 
怎麼講是最符合人的思維的位元組序,是因為從人的第一觀感來說 
低位值小,就應該放在記憶體地址小的地方,也即記憶體地址低位 
反之,高位值就應該放在記憶體地址大的地方,也即記憶體地址高位 

BE big-endian 
最直觀的位元組序 
地址低位儲存值的高位 
地址高位儲存值的低位 
為什麼說直觀,不要考慮對應關係 
只需要把記憶體地址從左到右按照由低到高的順序寫出 
把值按照通常的高位到低位的順序寫出 
兩者對照,一個位元組一個位元組的填充進去 

例子:在記憶體中雙字0x01020304(DWORD)的儲存方式 

記憶體地址 
4000 4001 4002 4003 
LE 04 03 02 01 
BE 01 02 03 04 

例子:如果我們將0x1234abcd寫入到以0x0000開始的記憶體中,則結果為
      big-endian   little-endian
0x0000   0x12       0xcd
0x0001   0x23       0xab
0x0002   0xab       0x34
0x0003   0xcd       0x12
x86系列CPU都是little-endian的位元組序. 

網路位元組順序是TCP/IP協議棧中規定好的一種資料表示格式,它與具體的CPU型別、作業系統等無關,從而可以保證資料在不同主機之間傳輸時能夠被正確解釋。網路位元組順序採用big endian排序方式。

為了進行轉換 bsd socket提供了轉換的函式 有下面四個

linux的原始碼(/include/netinet/in.h)

# if __BYTE_ORDER == __BIG_ENDIAN 
/* The host byte order is the same as network byte order, 
   so these functions are all just identity.  */ 
# define ntohl(x) (x) 
# define ntohs(x) (x) 
# define htonl(x) (x) 
# define htons(x) (x) 
# else 
#  if __BYTE_ORDER == __LITTLE_ENDIAN 
#   define ntohl(x) __bswap_32 (x) 
#   define ntohs(x) __bswap_16 (x) 
#   define htonl(x) __bswap_32 (x) 
#   define htons(x) __bswap_16 (x) 
#  endif 
# endif


htons 把unsigned short型別從主機序轉換到網路序
htonl 把unsigned long型別從主機序轉換到網路序
ntohs 把unsigned short型別從網路序轉換到主機序
ntohl 把unsigned long型別從網路序轉換到主機序

在使用little endian的系統中 這些函式會把位元組序進行轉換 
在使用big endian型別的系統中 這些函式會定義成空巨集

 都是4個巨集函式:

 分析其中1個,htonl(x)我簡化為下:

  #define  htonl(x)  \  //連線符,連線下一行

  ((unsigned long ) \

( \

(((unsigned long)(x)&0x000000ff<<24)| \

(((unsigned long)(x)&0x0000ff00)<<8)| \

(((unsigned long)(x)&0x00ff0000)>>8)| \

(((unsigned long)(x)&0xff000000)>>24)\

))

這樣寫是方便好看一點,巨集的最後最好是用一個括號括起來,或者用do{}while0)包起來。

這樣可以防止巨集巢狀產生意想不到問題等,如果自己熟悉了就可以簡潔一點。上面那個巨集的作用是把4321變成1234(位元組擺放順序)。


一般c語言編寫程式的位元組序都是系統相關的(java的位元組碼是big-endian 和網路位元組序一樣,所以他和網路通訊不需要關心位元組序問題),如果要和其他平臺進行通訊,都要進行位元組序轉換,跨平臺開發時也應該注意保證只用一種位元組序 不然兩方的解釋不一樣就會產生bug。

網路上流傳一個測試自己系統是什麼位元組序函式程式碼:

byte_type get_sys_byte_order()

{

     union

    {

         int  b;

         char a[4];

     }U;

     U.b = 0x01;

     if(0x01 == U.a[0] )

     {

         return   little_endian_type;

      }

    else

      {

         return   big_endian_type;

      } 
} 
注:
1、網路與主機位元組轉換函式:htons ntohs htonl ntohl (s 就是short l是long h是host n是network)
2、不同的CPU上執行不同的作業系統,位元組序也是不同的,參見下表。
處理器         作業系統     位元組排序
Alpha            全部     Little endian
HP-PA             NT      Little endian
HP-PA            UNIX     Big endian
Intelx86         全部     Little endian <-----x86系統是小端位元組序系統
Motorola680x()   全部     Big endian
MIPS              NT      Little endian
MIPS             UNIX     Big endian
PowerPC           NT      Little endian
PowerPC          非NT     Big endian   <-----PPC系統是大端位元組序系統
RS/6000          UNIX     Big endian
SPARC            UNIX     Big endian
IXP1200 ARM核心  全部     Little endian 

四 位元組對齊

首先我看哈程式的優化種類:

Cpu級優化((讀記憶體),流水線,cache,現在多核等)->2進位制級(即01程式碼)優化(現在估計沒有人去做了)->彙編級(指令)優化->高階程式裡面的程式碼級優化(位運算,前++和後++,陣列和指標,if else和switch case等優化)->演算法優化(流程優化)->軟體架構級優化......

  而現在我們討論的位元組對齊屬於cpu級優化,可以加速cpu讀取記憶體時間。

什麼是位元組對齊:

現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何地址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體地址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的一個接一個的排放,這就是對齊。 
    對齊的作用和原因:各個硬體平臺對儲存空間的處理上有很大的不同。一些平臺對某些特定型別的資料只能從某些特定地址開始存取。比如有些架構的CPU在訪問一個沒有進行對齊的變數的時候會發生錯誤(比如高通平臺,一般的手機平臺都採用美國高通公司開發平臺,對於無線上網絡卡來說,現在都是多核,要麼是arm9+arm11,要麼是arm9+2QdspQ是表示高通的dsp處理器)等處理器架構,然而在Qdsp中,如果訪問了非對齊的記憶體,就會直接發生錯誤,直接把系統crush掉)那麼在這種架構下程式設計必須保證位元組對齊.其他平臺可能沒有這種情況,但是最常見的是如果不按照適合其平臺要求對資料存放進行對齊,會在存取效率上帶來損失。比如有些平臺每次讀都是從偶地址開始,如果一個int型(假設為32位系統)如果存放在偶地址開始的地方,那 麼一個讀週期就可以讀出這32bit,而如果存放在奇地址開始的地方,就需要2個讀週期,並對兩次讀出的結果的高低位元組進行拼湊才能得到該32bit資料。顯然在讀取效率上下降很多。 

一般的規則是,

1 對於基本資料型別對齊要求:

Char 型別一個位元組對齊,可以從任何記憶體地址讀取;

Short2個位元組,要求是從偶記憶體地址讀取;

Int 4個位元組(32位系統),要求是變數的記憶體地址必須被4整除;

Longint一樣(在32位系統中)

Double 8個位元組,要求是變數的記憶體地址必須被8整除。

c語言中存在structunion結構體型別,屬於複雜型別:

2  對於structunion對齊要求是:

其成員中自身對齊值最大的那個值 。

注:結構的總大小為結構的位元組邊界數(即該結構中佔用最大空間的變數的型別所佔用的位元組數)的倍數,對於結構體最終大小,還要參考,指定對齊值n

1)對於struct我們有:

s表示這個結構體,X(i)表示其第i個成員(按順序從上往下)所佔的大小;假使結構體有m個成員;

結構體的最終對齊值  

  其中基本型別對齊值:

  A(char) = 1;

  A(short) = 2;

  A(int) = 4;

  A(long) = 4;

  A(float) = 4;

  A(double) = 8;

    基本型別成員對齊值 Ax) = min(A(type),n );    公式1

A(type) 為基本型別成員對應的基本型別。

     A(s) = min(max(A(1),A(2),...,A(m)),n)       公式2

(這個一個遞迴函式,主要原因是成員Xi有可能也是一個結構體,巢狀型別)

 其中:

 由規則1可以得到公式 2的初始值

  struct結構體最終佔記憶體大小Xs

  定義H(x)表示前面x個成員最終佔記憶體大小;A(x)表示第x個成員的對齊值。可以有公式1給出,則:

If(H(x)%A(x+1) == 0)

  H(x+1)= H(x)+X(x+1);

Else

  H(x+1)= H(x)+A(x+1)-H(x)%A(x+1)+X(x+1); 

其中 H(1) = X1,A(1)= X1;  

                                    公式3

則:

IfH(m)%A(s) == 0)

   Xs = H(m);

Else

   Xs = H(m)+A(s)-H(m)%A(s); 

                                    公式

2)對於union我們有:

     U表示這個結構體,Xi表示其第i個成員(按順序從上往下)所佔的大小;假使結構體有m個成員;

      結構體的最終對齊值  A(u) = min(max(A(1),A(2),...,A(m)),n) 公式5

Union結構體最終佔記憶體大小Xu

   定義H(x)表示前面x個成員最終佔記憶體大小;A(x)表示第x個成員的對齊值。可以有公式1給出,則:

  H(x+1= max(X(x+1), H(x));

其中 H(1) = X1;

                                    公式6

   則:

IfH(m)%A(u) == 0)

   Xu = H(m);

Else

   Xu = H(m)+A(u)-H(m)%A(u); 

                                    公式

3  指定對齊值:

     如果我們想指定對齊值,可以在VC IDE中,可以這樣修改:[Project]|[Settings],c/c++選項卡CategoryCode Generation選項的Struct Member Alignment中修改,預設是8位元組,針對全部變數,如果想動態改變部分,在vc中可以用巨集命令 #pragma pack (n)時的指定對齊值n,#pragma pack()取消,之間的資料都是指定為n,但不一定為對齊n 最終的資料成員對齊值為: 自身對齊值和指定對齊值中小的那個值 。(這個很重要,請好好理解)。

4  結構中帶有結構
    不必考慮整個子結構,只考慮子結構的基本型別並參照前面的規則來分配空間。
 空結構(即不帶任何的方法和資料)佔用的1位元組的空間。

5  列舉中(enum 
   列舉始終佔用4位元組的空間。

6  結構中成員

    結構的靜態成員不對結構的大小產生影響,因為靜態變數的儲存位置與結構的例項地址無關。  

要理解上面的對齊規則,最好是分析一些典型的對齊例子:

例子1

   struct MyStruct 

  char dda; 
  double dda1; 
  int type 

}; 

預設指定對齊值n = 8(vc),其他自己檢視,n = 8

由公式得到此結構體的最終對齊值為 A(s) = 8

有上面公式2 ,3 可以得到 X(MyStruct)(=sizeof(MyStruct)) :

H(1) = 1, H(2) =(H(1)) 1+7+8 = 16; H(3) =(H(2)) 16+4 = 20;

X(s) = (H(3))20 + (A(s)-H(3)%A(s)) 4 = 24;

所以sizeofMyStruct) = 24

例子2

#pragma  pack2

 struct MyStruct 

  char dda;   A1) = 1 
  double dda1; A2) = 2 
  int type   A3) = 2 
}; 

#pragma  pack()

由公式1,2得到此結構體的最終對齊值為 A(s) = 2

有上面公式3 ,4 可以得到 X(MyStruct)(sizeof(MyStruct)) :

H(1) = 1, H(2) =(H(1)) 1+ (A(2)-H(1)%A(2)) 1+(X2)8 = 10; 因為H(2)%A(3)==0

所以 H(3) =(H(2)) 10+4 = 14;

因為H(3)%A(s) == 0;

所以X(s) = (H(3)) 14;

所以sizeofMyStruct) = 14;

例子3

   這裡有個結構體巢狀例子,對於結構體中的結構體成員,不要認為它的對齊方式就是他的大小,看下面的例子:

struct s1
{
char a[8]; 
};
struct s2
{
double d; 
};
struct s3
{
s1 s; 
char a; 
};
struct s4
{
s2 s; 
char a; 
};
預設指定對齊值n = 8

As1) = 1A(s2) =min(min(A(double), 8),8) =8 ; 

A(s3) = min(max(A(x1)=min(A(s1) = 1,8) = 1,A(x2) = 1),8) = 1;

A(s3) = min(max(A(x1)=min(A(s2) = 8,8) = 8,A(x2) = 1),8) = 8;

X(s1) = 8;

X(s2) = 8;

X(s3) = 9;

X(s4) = 16;

具體過程自己可以分析一下;

 例子 4

#pragma pack(4)

union u1

{

double b; A(1)  = 4

int a;    A(2)  = 4

}x1;

#pragma pack()

#pragma pack(8)

union u2

{

char a[13]; A(1) = 1

double b;  A(2) = 8

}x2;

#pragma pack()

A(u1)  = min(max(A(1),A(2))=4,n=4) = 4;

A(u2)  =min(max(A(1),A(2))=8,n=8) = 8;

對於u1H(1) = 8; H(2) = max(H(1)8,X(2)4) = 8;

因為H(2)%A(u1) == 0;

所以 X(u1) = H(2) = 8;

對於u2H(1) = 13, H(2)=max(H(1),X(2)8) = 13;

因為 H(2)%A(u2) !=0;

所以 X(u2) = H(2) + A(u2)-H(2)%A(u2)= 13+3=16;

也上只是一些測試例子,真實的結構體都比較龐大,一般用sizeof就可以了,但心裡要清楚,每個成員的偏移量和填充的位元組,這些都可以由上面的公式推出來,我這裡就暫時不推導了(但這個才是我們平時最應該注意的)。

五 總結

     對於位元組的理解其實這些還不夠,掌握這些只是作為頂級c程式設計師最基本的要求(路還很長),有細節需要參考一下cpu的手冊。其實在實際程式設計當中,出現位元組對齊的原因是通訊的要求,不管是通過tcp/ip(網際網路),這樣一般協議頭部都是一個位元組對齊,這樣對方解釋的時候是隻需按協議解析就正確了;或者是動態庫呼叫,給別人的介面函式對應引數,如果是沒有滿足位元組對齊的要求(不相同),如果進行強制型別轉換或者按偏移量訪問變數,就有可能出現錯誤(某些嵌入式cpu)或者意想不到問題,所以對於嵌入式開發的程式設計師最好是心裡有數。

    最後請希望自己成為頂級c程式設計師的coders,來設計一個memcpy函式,為什麼要設計這個函式呢,如果你看過很多大工程的程式碼,你就明白了,這個函式使用率相當高,strcpy這個的優化版本內部都是呼叫memcpy來完成,這是系統函式,每個平臺自己都實現了這個函式,而且裡面充滿奇淫巧計,呵呵,看看自己會長見識。

以下是高通平臺的
memcpy函式:

typedef  unsigned int uint_t;

typedef  unsigned char uchar_t;

void *

memcpy(void * d, const void *s,size_t n)

{

   size_t i;

   uint_t align = sizeof(uint_t ) -1;

   if( ((uint_t)d&align)| ((uint_t)s&align)| (n&align))

  {

     uchar_t  *dest = (uchar_t  *)d;

     uchar_t  *src = (uchar_t  *)s;

     for(i = 0; i < n; ++i)

     {

        *dest ++ = *src++;

     }

 }

 else

 {

     uint_t  *dest = (uint_t *)d;

     uint_t  *src = (uint_t *)d;

     n /=sizeof(uint_t );

     for(i = 1; i < n; ++i)

      {

        *dest ++ = *src++;

      }

 }

 return d;

}

注: 以上只是我學習中文件輸出,可能會有錯誤(什麼型別的錯誤都可能發生),我希望讀者能幫我一起改正,希望大家一起努力,朝頂級c程式設計師前進,讀者有什麼意見都可以在回覆中提出,我會繼續的,就像我前一篇文章所說一樣,目的把我學到的東西分享給大家,希望大家好好學

相關推薦

頂級c程式設計師 選學-1 深入理解位元組位元組位元組

                         深入理解位元組,位元組序與位元組對齊 一 總述    作為一個職業的coder玩家,首先應該對計算機的位元組有所瞭解。    我們經常談到的2進位制流,位元組(字元)流,資料型別流(針對程式設計),結構流等說法,2

程式設計師c++:第一課:格式cout

程式設計師之路   先舉個例子: #include <iostream> //匯入iostream庫 using namespace std; //宣告名稱空間 int main()

程式設計師c++:第二課:資料型別(1)

資料型別 舉個例子: #include <iostream> using namespace std; int main() { int a; //定義整數型變數a cin >> a; //輸入 long long b

我的程式設計師:自學Java

## 序章 時光疾馳,從事IT行業已兩年有餘。 16年11月開始自學Java,從此開啟自學之路,後來實習期自學大資料、python、爬蟲等,最終成長為一名平凡的程式設計師。回首望去,一路上的過往歷歷在目,有初學Java掌握皮毛後的沾沾自喜,也有遇到問題無法解決時的埋頭絕望。曾在學校的夜晚洋洋灑灑寫下筆記百十行

我的程式設計師02:大資料實習

實習一年,我從Java入門者成為了一名大資料開發。 ## 第一份實習offer 專升本的第一學年末,憑藉著自學Java拿到了人生的第一份Java開發的實習offer。我深知那時候我的Java水平有限,也深知能拿到offer並不是因為我多優秀,而是公司一批招了20多個人。 17年7月,收拾好行李,和舍友體驗

一個專科生的程式設計師

沒有BAT的offer,也沒有奮鬥史,甚至連一個最基本的offer都沒有,有的只是覺悟。 面臨高考         高考就是八仙過海,各顯神通,覺悟高的人可以從高一開始,將每一天都過得很充實,然後為了高考去努力學習,又或者很聰明的人

程式設計師參考1

原文地址:http://www.zuoxiaolong.com/html/article_184.html#http://www.zuoxiaolong.com/html/article_184.html# 引言      其實本來真的沒打算寫這篇文章,主要是LZ得記憶力不是很好,不像

我的程式設計師(開篇)

高中的時候,有次學校開了一個計算機語言培訓班,學費也不貴,學的是BASIC,第一次去試聽,老師講了a,b的值互換問題和進位制之間轉換問題,我聽得頭都大了,想不到還有這樣一種高中生都難以理解的東西,直到高考結束,成績還不錯,報考的是哈工大威海校區的軟體工程專業。 我不知道等待我的是什麼樣的難題

開啟全新奮鬥的程式設計師

     我,一個985學校大三在校生,就讀計算機學院,專業是網路與資訊保安,一個普普通通的轉專業生,能力一般,單身...........      由於各種原因,我以高於我們學校4分的成績光榮的進入了我們學校的末尾專業——農業機械化,

程式設計師

最近專案收尾了,突然閒下來,反而有點發慌,於是決定把專案中遇到的問題整理下來,避免再遇到會手足無措。此篇部落格我想寫給準備步入職場的新人,雖然我也不是什麼職場老江湖,但是我的經歷也許會幫到初入職場忐忑的你。 我是16年畢業的,混混沌沌幹了安卓1年,然

資深程式設計師(5)--agile開發

以“瀑布模型”為代表的傳統軟體開發模型針對軟體生命週期的各個階段提供了一套規範, 以期使工程的進展達到預期的目的。核心強調在軟體開發活動中, 所有的活動計劃, 日程安排, 交付工作都要直接或間接的和需求保持一致, 同時強調軟體需求必須形成“ 文件” 。這種基

程式設計師的重新思索

在IT這個行業從業已有六七年,自以為算得上是一位高手級人物。前段時間和某位IT業內前輩聊天,聊到一些技術性問題上的時候,竟被問得無地自容,頓時覺得以前高看了自己。 細細思索了一下自己的不足,覺得需要從以下幾點開始: 重新梳理基礎知識體系。 對於一位資深開

陳俊嶺的程式設計師(公眾號求關注方便交流)

如果覺得這篇文章對您有所啟發,歡迎關注我的公眾號,我會盡可能積極和大家交流,謝謝。   轉眼間已經研二了,突然想把以前看過的文獻總結總結與大家分享,留作紀念,方便以後參考。  1、深度追蹤:通過卷積網路進行差異特徵學習的視覺追蹤(DeepTrack:Learning Disc

我的程式設計師(英語的學習)

程式設計師本來就很辛苦了,但看不懂英語文件更讓一個程式設計師更加頭疼。英語對一個程式設計師來說還是很重要的,英語的學習需要日積月累,不怕大家笑話,我初中時的英語還是槓槓的,記得中考,我英語一題沒有錯,就作文扣了兩分,也許是初中的英語簡單吧,也許是高中沒有努力學習英語,不知道

我的程式設計師:11 年高考結束到 17 年日本修士的心路歷程

前言 友情提示,本文共 6970 字,請耐心閱讀閱讀。借這個機會可以舒展心中的話,很開心。希望大學新生看到我的經歷能從中學習到經驗與教訓。本文是作者多年總結經驗和心得,從大學教育對比,大學學習歷程,考研價效比高的學校推薦,海外留學經驗,技術積累,編碼學

程式設計師——一個老程式設計師剛上大學的學弟學妹的忠告

http://blog.csdn.net/immiao/article/details/44873921 始終認為,對一個初學者來說,IT界的技術風潮是不可追趕。 我時常看見自己的DDMM們把課本扔了,去買些價格不菲的諸如C#, VB.Net 這樣的大部頭,這讓我感

轉行程式設計師

    心血來潮,想記錄自己在技術上的成長之路。    本人國內211機械碩士畢業,91年的,16年3月畢業。本科機械設計,研究生紡織機械懂一點機電。讀研的時候做導師專案需要用到程式設計,自學了Java,然後就懵懵懂懂在沒人指點的情況下(導師不懂程式設計)搞起了程式設計。在這

ddyyxx的程式設計師

KMP演算法是一種線性時間複雜度的字串匹配演算法,它是對BF(Brute-Force,最基本的字串匹配演算法)的改進。對於給定的原始串S和模式串T,需要從字串S中找到字串T出現的位置的索引。KMP演算法由D.E.Knuth與V.R.Pratt和J.H.Morris同時發現,因此人們稱它為Knuth--Mor

Blank的程式設計師

  對於如何進行程式碼重構,一直有著很多種說法。很多人都認為應該將重構程式碼放在backlog裡。但是其實,這並不是一個理想的方法。   在專案剛剛開始的時候,你的程式碼很乾淨。   即使有的時候需要小小的繞一下路,但是這個時候我們可以輕鬆、平穩的新增功能。這個階段

資深程式設計師(1)--如何保證程式碼是沒安全漏洞的

一個偶然的機會需要競標一個大專案,需要參加甲方的資深架構師面試,事先有一點準備,如何保證程式碼是沒安全漏洞的,如何保證程式碼是clean的,要了解設計模式,能畫出一個UML class圖,如何做持續整合和部署,agile開發 上面的這些對於大多數程式設計師可能