PIXNET Logo登入

Iver's Blog

跳到主文

想到就記錄

部落格全站分類:生活綜合

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 6月 29 週一 201510:25
  • [轉貼]C/C++ 學習歷程分享

進入C語言都有一道門檻,第一個最基本的是指標,之後還有二維陣列、指標陣列,學著學著又發現紥根基的工作不能少...
以下正轉載來的,轉自Edison.X. Blog,寫的相當不錯。
怎麼學c語言、怎麼挑書、要挑什麼書",這個問題聽過蠻多遍了,提供自己學習 C/C++ 的歷程讓各位參考。以下的說明都是以個人主觀的立場,當然我不是什麼大師,這些都參考就好。由於當初筆者接觸時,就是 C ,若想學其它像是 VB, JAVA, C# 等程式語言,這篇文章仍可給予一些幫助與參考。
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(1) 人氣(1,544)

  • 個人分類:C
▲top
  • 7月 06 週二 201018:27
  • 組合語言

指令表示法
li $s0, 1 指示將 s0 暫存器的數值設定為 1
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(0) 人氣(924)

  • 個人分類:C
▲top
  • 6月 10 週四 201010:06
  • Compile睹到會卡住的情形

Q1:Compile的時候,明明有定義某個data type, compiler確一直不認得。
A:Clean all 再重新compile。 
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(0) 人氣(67)

  • 個人分類:C
▲top
  • 12月 10 週四 200919:04
  • C語言新手十誡(The Ten Commandments for Newbie C Programmers)

這是補充的: C 信徒的摩西十戒
以下是網路上轉來的~
by Khoguan Phuann
請注意:
(1) 本篇旨在提醒新手,避免初學常犯的錯誤(其實老手也常犯:-Q)。
  但不能取代完整的學習,請自己好好研讀一兩本 C 語言的好書,
  並多多實作練習。
(2) 強烈建議新手先看過此文再發問,你的問題極可能此文已經提出並
  解答了。
(3) 以下所舉的錯誤例子如果在你的電腦上印出和正確例子相同的結果,
  那只是不足為恃的一時僥倖。
(4) 不守十誡者,輕則執行結果的輸出數據錯誤,或是程式當掉,重則
  引爆核彈、毀滅地球(如果你的 C 程式是用來控制核彈發射器的話)。
一、你不可以使用尚未給予適當初值的變數。
  int accumulate(int max) /* 從 1 累加到 max,傳回結果 */
  {
  int sum; /* 未給予初值的區域變數,其內容值是垃圾 */
  int num;
  for (num = 1; num <= max; num++) {
  sum += num;
  }
  return sum;
  }
  正確例子:
  int accumulate(int max)
  {
  int sum = 0; /* 正確的賦予適當的初值 */
  int num;
  for (num = 1; num <= max; num++) {
  sum += num;
  }
  return sum;
  }
二、你不可以存取超過陣列既定範圍的空間。
  錯誤例子:
  int str[5];
  int i;
  for (i = 0; i <= 5; i++) str[i] = i;
  正確例子:
  int str[5];
  int i;
  for (i = 0; i < 5; i++) str[i] = i;
  說明:宣告陣列時,所給的陣列元素個數值如果是 N, 那麼我們在後面
  透過 [索引值] 存取其元素時,所能使用的索引值範圍是從 0 到 N-1,
  也就是 C 和 C++ 的陣列元素是從第 0 個開始算起,最後一個元素的
  索引值是 N-1, 不是 N。
  C/C++ 為了執行效率,並不會自動檢查陣列索引值是否超過陣列邊界,
  我們要自己寫程式來確保不會越界。一旦越界,將導致無法預期的後果。
三、你不可以提取(dereference)不知指向何方的指標(包含 null 指標)。
  錯誤例子:
  char *pc1; /* 未給予初值,不知指向何方 */
  char *pc2 = 0; /* pc2 起始化為 null pointer */
  *pc1 = 'a'; /* 將 'a' 寫到不知何方,錯誤 */
  *pc2 = 'b'; /* 將 'b' 寫到「位址0」,錯誤 */
  正確例子:
  char c; /* c 的內容尚未起始化 */
  char *pc1 = &c; /* pc1 指向字元變數 c */
  /* 動態分配 10 個 char(其值未定),並將第一個char的位址賦值給 pc2 */
  char *pc2 = (char *)malloc(10);
  *pc1 = 'a'; /* c 的內容變為 'a' */
  pc2[0] = 'b'; /* 動態配置來的第 0 個字元,內容變為 'b'
  /* 最後記得 free() 掉 malloc() 所分配的空間 */
  free(pc2);
  說明:指標變數必需先指向某個明確的東西(object),才能進行操作。
四、你不可以將字串常數賦值(assign)給 char* 變數,然後透過該變數
  改寫字串的內容(只能讀不能寫)。
  錯誤例子:
  char* pc = "john";
  *pc = 'J';
  printf("Hello, %s\n", pc);
  正確例子:
  char pc[] = "john";
  *pc = 'J'; /* 或 pc[0] = 'J'; */
  printf("Hello, %s\n", pc);
  說明:字串常數的內容是唯讀的。上面的錯誤例子,是將其內容所在的位址賦
  值給字元指標 pc, 我們透過指標只可以去讀該字串常數的內容,而不應該做
  寫入的動作。而正確例子,則是另外宣告一個獨立的字元陣列,它的大小我們
  未明文指定([]),編譯器會自動將其設為剛好可以容納後面的字串常數起始
  值的大小,包括字串後面隱含的 '\0' 字元,並將字串常數的內容複製到字元
  陣列中,因此可以自由的對該字元陣列的內容進行讀和寫。
  錯誤例子(2):
  char *s1 = "Hello, ";
  char *s2 = "world!";
  /* strcat() 不會另行配置空間,只會將資料附加到 s1 所指唯讀字串的後面,
  造成寫入到程式無權碰觸的記憶體空間 */
  char *s3 = strcat(s1, s2);
  正確例子(2):
  /* s1 宣告成陣列,並保留足夠空間存放後續要附加的內容 */
  char s1[20] = "Hello, ";
  char *s2 = "world!";
  /* 因為 strcat() 的返回值等於第一個參數值,所以 s3 就不需要了 */
  strcat(s1, s2);
五、你不可以對尚未分配所指空間的 char* 變數,進行(字串)陣列的相關操作。
  其他型別的指標亦然。
  錯誤例子:
  char *name; /* name 尚未指向有效的空間 */
  printf("Your name, please: ");
  gets(name);
  printf("Hello, %s\n", name);
  正確例子(1):
  /* 如果編譯期就能決定字串的最大空間,那就不要宣告成 char* 改用 char[] */
  char name[21]; /* 字串最長 20 個字元,另加一個 '\0' */
  printf("Your name, please: ");
  gets(name);
  printf("Hello, %s\n", name);
  正確例子(2):
  /* 若是在執行時期才能決定字串的最大空間,則需利用 malloc() 函式來動態
  分配空間 */
  size_t length;
  char *name;
  printf("請輸入字串的最大長度(含null字元): ");
  scanf("%u", &length);
  name = (char *)malloc(length);
  printf("Your name, please: ");
  scanf("%s", name);
  printf("Hello, %s\n", name);
  /* 最後記得 free() 掉 malloc() 所分配的空間 */
  free(name);
  注意:上例用 gets() 或 scanf() 來讀入字串,是不安全的。 因為這些函式
  不會幫我們檢查使用者所輸入的字串長度是否超過我們所分配的 buffer 空間,
  很可能會發生 buffer overflow。比較安全的做法是用 fgets() 來取代。如:
  char *p;
  char name[21];
  printf("Your name, please: ");
  fgets(name, sizeof(name), stdin);
  /* fgets()會連行末的'\n'也讀進字串中,所以要找出存入'\n'的位置,填入 '\0'
  if ((p = strchr(name, '\n')) != NULL)
  *p = '\0';
  printf("Hello, %s\n", name);
六、你不可以在函式中回傳一個指向區域性自動變數的指標。否則,會得到垃圾值。
  [感謝 gocpp 網友提供程式例子]
  錯誤例子:
  char *getstr(char *name)
  {
  char buf[30] = "hello, "; /*將字串常數"hello, "的內容複製到buf陣列*/
  strcat(buf, name);
  return buf;
  }
  說明:區域性自動變數,將會在離開該區域時(本例中就是從getstr函式返回時)
  被消滅,因此呼叫端得到的指標所指的字串內容就失效了。【不過,倒是可以從
  函式中直接傳回字串常數,賦值給呼叫端的一個 const char * 變數,它既是唯
  讀的(參見第四誡),同時也具有恒常的儲存期(static storage duration),其
  內容將一直有效。】
  正確例子:
  void getstr(char buf[], int buflen, char const *name)
  {
  char const s[] = "hello, ";
  assert(strlen(s) + strlen(name) < buflen);
  strcpy(buf, s);
  strcat(buf, name);
  }
  [針對字串操作,C++提供了更方便安全的 string class, 能用就盡量用]
  #include <string>
  using std::string;
  string getstr(string const &name)
  {
  return string("hello, ") += name;
  }
七、你不可以只做 malloc(), 而不做相應的 free(). 否則會造成記憶體漏失。
  但若不是用 malloc() 所得到的記憶體,則不可以 free()。已經 free()了
  所指記憶體的指標,在它指向另一塊有效的動態分配得來的空間之前,不可
  以再被 free(),也不可以提取(dereference)這個指標。
  [C++] 你不可以只做 new, 而不做相應的 delete.
八、你不可以在數值運算、賦值或比較中隨意混用不同型別的數值,而不謹慎考
  慮數值型別轉換可能帶來的「意外驚喜」(錯愕)。必須隨時注意數值運算
  的結果,其範圍是否會超出變數的型別。
  錯誤例子(1):
  unsigned int sum = 2000000000 + 2000000000; /* 20 億 */
  double f = 10 / 3;
  正確例子(1):
  /* 全部都用 unsigned int, 注意數字後面的 u, 大寫 U 也成 */
  unsigned int sum = 2000000000u + 2000000000u;
  /* 或是用顯式的轉型 */
  unsigned int sum = (unsigned int)2000000000 + 2000000000;
  double f = 10.0 / 3.0;
  說明:在目前最普遍的32位元PC作業平台上,整數常數2000000000的型別為
  signed int(簡寫為 int),相加後,其結果仍為 int, 但是 signed int
  放不下 4000000000, 造成算術溢位(arithmetic overflow),很可能無法
  將正確的值指派給 unsigned int sum,縱使 unsigned int 放得下4000000000
  的數值。注意:寫成
  unsigned int sum = (unsigned int)(2000000000 + 2000000000);
  也是不對的。
  例子(2):(感謝 sekya 網友提供)
  unsigned char a = 0x80;
  char b = 0x80; /* implementation-defined result */
  if( a == 0x80 ) { /* 恒真 */
  printf( "a ok\n" );
  if( b == 0x80 ) { /* 不一定恒真 */
  printf( "b ok\n" );
  }
  說明:在將 char 型別定義為範圍從 -128 至 +127 的系統上,int 0x80
  (其值等於 +128)要轉成 char 會放不下,會產生編譯器自行定義的值。
  這樣的程式就不具可移植性了。
九、你不可以在一個運算式(expression)中,對一個基本型態的變數修改其值
  超過一次以上。否則,將導致未定義的行為(undefined behavior)。
  錯誤例子:
  int i = 7;
  int j = ++i + i++;
  正確例子:
  int i = 7;
  int j = ++i;
  j += i++;
  你也不可以在一個運算式(expression)中,對一個基本型態的變數修改其值,
  而且還在同一個式子的其他地方為了其他目的而存取該變數的值。(其他目的,
  是指不是為了計算這個變數的新值的目的)。否則,將導致未定義的行為。
  錯誤例子:
  int arr[5];
  int i = 0;
  arr[i] = i++;
  正確例子:
  int arr[5];
  int i = 0;
  arr[i] = i;
  i++;
  [C++程式]
  錯誤例子:
  int i = 10;
  cout << i << "==" << i++;
  正確例子:
  int i = 10;
  cout << i << "==";
  cout << i++;
十、你不可以在macro的定義中,不為它的參數個別加上括號。
  錯誤例子:
  #include <stdio.h>
  #define SQUARE(x) (x * x)
  int main()
  {
  printf("%d\n", SQUARE(10-5));
  return 0;
  }
  正確例子:
  #include <stdio.h>
  #define SQUARE(x) ((x) * (x))
  int main()
  {
  printf("%d\n", SQUARE(10-5));
  return 0;
  }
  說明:如果是用 C++, 請多多利用 inline function 來取代上述的 macro,
  以免除 macro 定義的種種危險性。如:
  inline int square(int x) { return x * x; }
  macro 定義出的「偽函式」至少缺乏下列數項函式本有的能力:
  (1) 無法進行參數型別的檢查。
  (2) 無法遞迴呼叫。
  (3) 無法用 & 加在 macro name 之前,取得函式位址。
  (4) 呼叫時往往不能使用具有 side effect 的引數。例如:
  錯誤例子:(感謝 yaca 網友提供)
  #define MACRO(x) (((x) * (x)) - ((x) * (x)))
  int main()
  {
  int x = 3;
  printf("%d\n", MACRO(++x));
  return 0;
  }
  MACRO(++x) 展開來後變成 (((++x) * (++x)) - ((++x) * (++x)))
  違反了第九誡。在 gcc 4.3.3 下的結果是 -24, 在 vc++ 下是 0.
後記:從「古時候」流傳下來一篇文章
  "The Ten Commandments for C Programmers"(Annotated Edition)
  by Henry Spencer
  http://www.lysator.liu.se/c/ten-commandments.html
  一方面它不是針對 C 的初學者,一方面它特意模仿中古英文
  聖經的用語,寫得文謅謅。所以我現在另外寫了這篇,希望
  能涵蓋最重要的觀念以及初學甚至老手最易犯的錯誤。
作者:潘科元(Khoguan Phuann) (c)2005. 感謝 ptt.cc BBS 的 C_and_CPP
  看板眾多網友提供寶貴意見及程式實例。
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(0) 人氣(1,395)

  • 個人分類:C
▲top
  • 8月 02 週日 200923:06
  • C/C++語言struct深層探索

1. struct的巨大作用
  面對一個人的大型C/C++程式時,只看其對struct的使用情況我們就可以對其編寫者的編程經驗進行評估。因為一個大型的C/C++程式,勢必要涉及一些(甚至大量)進行資料組合的結構體,這些結構體可以將原本意義屬於一個整體的資料組合在一起。從某種程度上來說,會不會用struct,怎樣用struct是區別一個開發人員是否具備豐富開發經歷的標誌。
  在網路協定、通信控制、嵌入式系統的C/C++編程中,我們經常要傳送的不是簡單的位元組流(char型陣列),而是多種資料組合起來的一個整體,其表現形式是一個結構體。
  經驗不足的開發人員往往將所有需要傳送的內容依順序保存在char型陣列中,通過指標偏移的方法傳送網路報文等資訊。這樣做編程複雜,易出錯,而且一旦控制方式及通信協定有所變化,程式就要進行非常細緻的修改。
  一個有經驗的開發者則靈活運用結構體,舉一個例子,假設網路或控制協定中需要傳送三種報文,其格式分別為packetA、packetB、packetC:
struct structA
{
int a;
char b;
};
struct structB
{
char a;
short b;
};
struct structC
{
int a;
char b;
float c;
}
  優秀的程式設計者這樣設計傳送的報文:
struct CommuPacket
{
int iPacketType;  //報文類型標誌
union      //每次傳送的是三種報文中的一種,使用union
{
struct structA packetA;
struct structB packetB;
struct structC packetC;
}
};
  在進行報文傳送時,直接傳送struct CommuPacket一個整體。
  假設發送函數的原形如下:
// pSendData:發送位元組流的首位址,iLen:要發送的長度
Send(char * pSendData, unsigned int iLen);
發送方可以直接進行如下調用發送struct CommuPacket的一個實例sendCommuPacket:
Send( (char *)&sendCommuPacket , sizeof(CommuPacket) );
假設接收函數的原形如下:
// pRecvData:發送位元組流的首位址,iLen:要接收的長度
//返回值:實際接收到的位元組數
unsigned int Recv(char * pRecvData, unsigned int iLen);
  接收方可以直接進行如下調用將接收到的資料保存在struct CommuPacket的一個實例recvCommuPacket中:
Recv( (char *)&recvCommuPacket , sizeof(CommuPacket) );
  接著判斷報文類型進行相應處理:
switch(recvCommuPacket. iPacketType)
{
case PACKET_A:
… //A類報文處理
break;
case PACKET_B:
…  //B類報文處理
break;
case PACKET_C:
… //C類報文處理
break;
}
  以上程式中最值得注意的是
Send( (char *)&sendCommuPacket , sizeof(CommuPacket) );
Recv( (char *)&recvCommuPacket , sizeof(CommuPacket) );
  中的強制類型轉換:(char *)&sendCommuPacket、(char *)&recvCommuPacket,先取地址,再轉化為char型指標,這樣就可以直接利用處理位元組流的函數。
  利用這種強制類型轉化,我們還可以方便程式的編寫,例如要對sendCommuPacket所處記憶體初始化為0,可以這樣調用標準庫函數memset():
memset((char *)&sendCommuPacket,0, sizeof(CommuPacket));
2. struct的成員對齊
  Intel、微軟等公司曾經出過一道類似的面試題:
1. #include
2. #pragma pack(8)
3. struct example1
4. {
5. short a;
6. long b;
7. };
8. struct example2
9. {
10. char c;
11. example1 struct1;
12. short e;
13. };
14. #pragma pack()
15. int main(int argc, char* argv[])
16. {
17. example2 struct2;
18. cout << sizeof(example1) << endl;
19. cout << sizeof(example2) << endl;
20. cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2)
<< endl;
21. return 0;
22. }
  問程式的輸入結果是什麼?
  答案是:
8
16
4
  不明白?還是不明白?下麵一一道來:
2.1 自然對界
  struct是一種複合資料類型,其構成元素既可以是基本資料類型(如int、long、float等)的變數,也可以是一些複合資料類型(如array、struct、union等)的資料單元。對於結構體,編譯器會自動進行成員變數的對齊,以提高運算效率。缺省情況下,編譯器為結構體的每個成員按其自然對界(natural alignment)條件分配空間。各個成員按照它們被聲明的順序在記憶體中順序存儲,第一個成員的位址和整個結構的位址相同。
  自然對界(natural alignment)即默認對齊方式,是指按結構體的成員中size最大的成員對齊。
  例如:
struct naturalalign
{
char a;
short b;
char c;
};
  在上述結構體中,size最大的是short,其長度為2位元組,因而結構體中的char成員a、c都以2為單位對齊,sizeof(naturalalign)的結果等於6;
  如果改為:
struct naturalalign
{
char a;
int b;
char c;
};
  其結果顯然為12。
2.2指定對界
  一般地,可以通過下面的方法來改變缺省的對界條件:
  • 使用虛擬指令#pragma pack (n),編譯器將按照n個位元組對齊;
  • 使用虛擬指令#pragma pack (),取消自定義位元組對齊方式。
  注意:如果#pragma pack (n)中指定的n大於結構體中最大成員的size,則其不起作用,結構體仍然按照size最大的成員進行對界。
  例如:
#pragma pack (n)
struct naturalalign
{
char a;
int b;
char c;
};
#pragma pack ()
  當n為4、8、16時,其對齊方式均一樣,sizeof(naturalalign)的結果都等於12。而當n為2時,其發揮了作用,使得sizeof(naturalalign)的結果為8。
  在VC++ 6.0編譯器中,我們可以指定其對界方式,其操作方式為依次選擇projetct > setting > C/C++功能表,在struct member alignment中指定你要的對界方式。
  另外,通過__attribute((aligned (n)))也可以讓所作用的結構體成員對齊在n位元組邊界上,但是它較少被使用,因而不作詳細講解。
2.3 面試題的解答
  至此,我們可以對Intel、微軟的面試題進行全面的解答。
  程式中第2行#pragma pack (8)雖然指定了對界為8,但是由於struct example1中的成員最大size為4(long變數size為4),故struct example1仍然按4位元組對界,struct example1的size為8,即第18行的輸出結果;
  struct example2中包含了struct example1,其本身包含的簡單資料成員的最大size為2(short變數e),但是因為其包含了struct example1,而struct example1中的最大成員size為4,struct example2也應以4對界,#pragma pack (8)中指定的對界對struct example2也不起作用,故19行的輸出結果為16;
  由於struct example2中的成員以4為單位對界,故其char變數c後應補充3個空,其後才是成員struct1的記憶體空間,20行的輸出結果為4。
3. C和C++間struct的深層區別
  在C++語言中struct具有了“類” 的功能,其與關鍵字class的區別在於struct中成員變數和函數的默認訪問許可權為public,而class的為private。
  例如,定義struct類和class類:
struct structA
{
char a;
…
}
class classB
{
char a;
…
}
  則:
struct A a;
a.a = 'a'; //訪問public成員,合法
classB b;
b.a = 'a'; //訪問private成員,不合法
  許多文獻寫到這裏就認為已經給出了C++中struct和class的全部區別,實則不然,另外一點需要注意的是:
  C++中的struct保持了對C中struct的全面相容(這符合C++的初衷——“a better c”),因而,下面的操作是合法的:
//定義struct
struct structA
{
char a;
char b;
int c;
};
structA a = {'a' , 'a' ,1}; // 定義時直接賦初值
  即struct可以在定義的時候直接以{ }對其成員變數賦初值,而class則不能,在經典書目《thinking C++ 2nd edition》中作者對此點進行了強調。
4. struct編程注意事項
  看看下面的程式:
1. #include
2. struct structA
3. {
4. int iMember;
5. char *cMember;
6. };
7. int main(int argc, char* argv[])
8. {
9. structA instant1,instant2;
10.char c = 'a';
11. instant1.iMember = 1;
12. instant1.cMember = &c;
13.instant2 = instant1;
14.cout << *(instant1.cMember) << endl;
15.*(instant2.cMember) = 'b';
16. cout << *(instant1.cMember) << endl;
17. return 0;
}
  14行的輸出結果是:a
  16行的輸出結果是:b
  Why?我們在15行對instant2的修改改變了instant1中成員的值!
  原因在於13行的instant2 = instant1賦值語句採用的是變數逐個拷貝,這使得instant1和instant2中的cMember指向了同一片記憶體,因而對instant2的修改也是對instant1的修改。
  在C語言中,當結構體中存在指標型成員時,一定要注意在採用賦值語句時是否將2個實例中的指標型成員指向了同一片記憶體。
  在C++語言中,當結構體中存在指標型成員時,我們需要重寫struct的拷貝構造函數並進行“=”操作符重載。
轉載自CSDN
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(0) 人氣(3,992)

  • 個人分類:C
▲top
  • 2月 20 週五 200916:36
  • 解釋EOF

根本沒有什麽文件結束符。 如果有的話空文件不是還要占一個字節的結束符? EOF是什麽?它就是-1。它不過是C例程裏的一個常量,當碰到文件結尾時,就返回-1。 問題的根本是你錯誤的認為磁盤的文件結尾還有一個字符專門表示文件的結束,呵呵,沒有這個字符,你想啊,每讀一個字符還要比較一下它是否等于“空想的文件結束符“,是不是太低效了點呢。那是如何判斷文件是否已經結束的?中斷、異常。
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(0) 人氣(111)

  • 個人分類:C
▲top
  • 2月 04 週三 200920:20
  • Bit Field





規則是以structure裡最佔記憶体空間的資料型態為單位,比如int佔 4 bytes,當不滿 4 bytes 時,遇到另一種型態就把記憶体填滿至 4 bytes,從下一個 4 bytes 開始放下一個變數。
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(2) 人氣(6,137)

  • 個人分類:C
▲top
  • 11月 21 週五 200817:08
  • My Function

以byte為單位,把記憶體的內容倒過來排void memRev_fun(void* memBuf, int byteLength)
{
  int front=0, rear;
  unsigned char tmp;
  rear = byteLength-1; //array index start from 0
  if(byteLength%2 != 0)
  {
  while(front+1 != rear-1) //odd
  {
  tmp = *(((unsigned char*)memBuf)+front);
  *(((unsigned char*)memBuf)+front) = *(((unsigned char*)memBuf)+rear);
  *(((unsigned char*)memBuf)+rear) = tmp;
  front++;
  rear--;
  }
  }
  else
  {
  while(front < rear) //even
  {
  tmp = *(((unsigned char*)memBuf)+front);
  *(((unsigned char*)memBuf)+front) = *(((unsigned char*)memBuf)+rear);
  *(((unsigned char*)memBuf)+rear) = tmp;
  front++;
  rear--;
  }
  }
}
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(0) 人氣(41)

  • 個人分類:C
▲top
  • 11月 09 週日 200816:18
  • Function Point

typedef void (*function_TYP)(void);
static function_TYP virtual_function_name=0;
void function_name()//void may be replaced by function_TYP
{
definition;
}
void function(function_TYP function_name)
{
virtual_function_name = function_name;
}
void a()
{//check virtual function is replaced by function point or not.
if(virtual_function_name)
(virtual_function_name)();
}
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(0) 人氣(217)

  • 個人分類:C
▲top
  • 11月 09 週日 200816:16
  • 觀念

C/C++ 的 Header file 不適合在裡面宣告實體物件的。因為做為一個 header file 可能會有很多程式檔含入(include)該Header file。如果你宣告了一個物件在裡面,編譯器會給你一個難堪的"重覆定義"的錯誤訊息。
通常的做法是,你應宣告全域物件在各自所屬的程式檔中,而其它要用到該物件的程式則宣告該全域物件為 external 即可。
現在的問題是,若有一個全域物件有許多的程式檔要用到,例如二十個檔案要使用,那麼要二十個檔案都要寫 external 宣告是非常麻煩的事!如果編譯器能聰明一點,在Header file宣告了全域變數,它
實 際只產一個物件,而其它所有含入這 Header file 的程式就全部以external 在參考那唯一產生的物件,豈不佳妙!?其實也真的有這樣的編譯器來幫忙"懶惰"的程式師(如 MS C 5.x 以前的版本)。但這是不正規的編譯器,也會延生其它問題(例如程員把原本應為兩個不同的物件卻寫成了同名)。所以絕大部份的編譯器是不允許你宣告物件在 Header file 給兩個以上的程式檔含入的。
//程式檔 MyLib.C
code:
#define MyLib_C
#include ".........."
#include "MyLib.H"
#undef MyLib_C
::::::::::::::::::::::::::::::::::::::::::
int function1(...)
{
:::::::::::::::::
}
int function2(...)
{
:::::::::::::::::
}
::::::::::::::::::::::::::::::::::::::::::
//其它含入 MyLib.H 的程式檔
code:
#include ".........."
#include "MyLib.H"
#include ".........."
::::::::::::::::::::::::::::::::::::::::::
//Header file MyLib.H
code:
::::::::::::::::::::::::::::::::::::::::::
int function1(...);
int function2(...);
#ifdef MyLib_C
#define AUTOEXT
#else //MyLib_C
#define AUTOEXT extern
#endif //MyLib_C
AUTOEXT int LastErrorNo;
::::::::::::::::::::::::::::::::::::::::::
#undef AUTOEXT
這樣子MyLib.C本身和其它用到MyLib.C全域物件的程式檔都可以放心
的含入 MyLib.H 了!
____________________________________________________________________________________
這 種方式是所謂的 Header Shield, 一般常見不是這樣用的(基本上, 這個例子是畫蛇添足 ), 主要常用在避免 header 循環 include 的問題, 比如 A.h include B.h, B.h include C.h, C.h include A.h, 可能不知道他們比次的關係造成一個 loop 了, 於是你在某個本文檔 #include &quto;A.h&quto; 便會出現問題, preprocessor 在處理 #include directive 時會有陷入循環的情形.
好的習慣是在寫每一個 header 都為其準備一個 shield:
code:
/* A.h */
#ifndef __A_H__
#define __A_H__
#include
#include
/* var/function declaration
#endif
B.h/C.h 也都是仿照這樣的方式, 照樣就可以避免循環引入 header 的問題.
另 外這種 header shield 也有用來作條件式編譯, 或是作 cross compile 的工作, 你在 A 平台用某工具(SDK) make 出 A 平台的可執行檔作測試, 要 release 時得 cross compile 成 target 平台的可執行檔, 但因平台差異可能需要對 source code 作些調整, 當然不是每次都去動 source 囉, 就可以利用這些技巧.
____________________________________________________________________________________
ANSI C 本來就規定 extern int LastErrorNo; 宣告之後可以出現 lastErrorNo 的定義, 所以你可以把
code:
extern int LastErrorNo;
寫 在 MyLib.h, 在任何需要 MyLib 的本文檔 include MyLib.h, 把 LastErrorNo 的定義寫在 MyLib.c 檔即可, 當然 MyLib.c 是一定會 include MyLib.h 的, 於是 LastErrorNo 的宣告和定義會出現在同一個本文檔中, 但這是正規的 ANSI C 寫法, 這樣本來就是符合惟一定義的規則.
把這一行:
code:
int LastErrorNo;
寫在 MyLib.c 檔中.
你想想看為什麼可以在 .c 檔案前頭先宣告:
code:
int add(int, int);
然後在之後才定義 add function 呢?
code:
int add(int a, int b)
{
return a + b;
}
變 數和函式都是一樣的, 如果你想避免你的函式及變數不必程式其他部分使用, 有點像 OOP 的隱藏作用, 你就在變數及函式定義時加上 static, 當然 header 就不需要提供這些不想被連結的變數或函式的宣告; 以 static 來指定內部連結性之後, 即使程式他處有出現同名變數或函式的宣告, 如果 linker 在所有的本文檔都找不到其定義, 就會有 linker error, 絕不會連結到你不想被連結的部分(static 修飾過的).
(繼續閱讀...)
文章標籤

lver76 發表在 痞客邦 留言(0) 人氣(2,261)

  • 個人分類:C
▲top
12»

個人資訊

lver76
暱稱:
lver76
分類:
生活綜合
好友:
累積中
地區:

文章搜尋

文章分類

toggle Life (4)
  • Health (1)
  • 碎碎念 (4)
  • 雜七雜八 (4)
  • 文章 (2)
toggle Image (3)
  • Wallpaper (0)
  • Beauty (0)
  • 風景圖 (1)
toggle Travel (5)
  • 國外旅行 (0)
  • 台灣 (4)
  • 大陸 (2)
  • Manual (1)
  • 美食 (1)
toggle Music (6)
  • 老歌 (4)
  • 歐美音樂 (45)
  • Musical (5)
  • JP_Koera (12)
  • 中文 (6)
  • 韓國 (1)
toggle Video (2)
  • Funny (2)
  • 摔角 (1)
toggle Finance (5)
  • 房地產 (4)
  • 金融商品 (2)
  • Creative (0)
  • 財經 (0)
  • 股市分析 (0)
toggle IT (12)
  • C (17)
  • Linux (22)
  • APM (1)
  • MySQL (1)
  • Development Tool (4)
  • Software (2)
  • Network (1)
  • Windows (0)
  • VB.Net (1)
  • C++ (2)
  • Video (2)
  • MIPS (2)
  • 未分類文章 (1)

熱門文章

  • (17,959)亞洲樂園
  • (11,014)C語言巨集定義技巧
  • (3,992)C/C++語言struct深層探索
  • (2,573)Pragma
  • (2,558)NTFS下用ghost備份
  • (2,104)volatile
  • (1,198)Install 嘸蝦米 on Fedora 5
  • (373)八達嶺長城
  • (111)解釋EOF
  • (27)印度服務生抓狂

最新文章

  • [轉貼]C/C++ 學習歷程分享
  • 中国香港真功夫武打明星
  • 費翔 - 吻别
  • 费翔 - 我們的幸福呢
  • 张琪 - 江山万里心
  • 月下對口
  • 水木年華 - 一生有你
  • C++ Debug 筆記
  • Bach - Cello Suite No.1 i-Prelude
  • 久石讓:送行者~禮儀師的樂章

最新留言

  • [25/07/13] 訪客 於文章「孫子兵法(原文加白話翻譯)...」留言:
    ✌️...
  • [24/05/20] 張龍鳳 於文章「孫子兵法(原文加白話翻譯)...」留言:
    商店奶奶說ㄧ次,金寧鄉惡魔、鄉公所惡妖(工廠懷孕、上班瓶孕)...
  • [23/04/27] OREO ROCK 於文章「孫子兵法(原文加白話翻譯)...」留言:
    很有幫助的文章&#128402;...
  • [23/04/18] chung 於文章「中国香港真功夫武打明星...」留言:
    為何Top 1 & Top 2 都是李小龍? 再細看 ...
  • [22/08/09] wenshu 於文章「孫子兵法(原文加白話翻譯)...」留言:
    感謝分享...
  • [22/04/14] 訪客 於文章「亞洲樂園...」留言:
    原本在搜尋引擎找出一堆 Blog 文章,不知哪幾篇值得花時間...
  • [21/12/25] 康藥本鋪 kmed.tw 於文章「孫子兵法(原文加白話翻譯)...」留言:
    康藥本鋪 https://kmed.tw 康藥本...
  • [21/12/17] 康藥本舖 kmed.tw 於文章「孫子兵法(原文加白話翻譯)...」留言:
    德國黑倍 https://kmed.tw/index.p...
  • [21/12/11] aksqfoooii 於文章「孫子兵法(原文加白話翻譯)...」留言:
    三體牛鞭 https://kmed.tw/ind...
  • [21/08/24] jwang0189 於文章「孫子兵法(原文加白話翻譯)...」留言:
    非常實用的文章,謝謝提供,已點廣告表示支持 https://...

誰來我家

參觀人氣

  • 本日人氣:
  • 累積人氣: