欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
曾讓我哭笑不得抓狂的C語(yǔ)言

1.關(guān)于+=以及-=

 這是兩個(gè)運算符,但你否有過(guò)這種經(jīng)歷:

  1. int temp;  
  2. char i  
  3. for(i=0;i<MAX;i++)  
  4. {  
  5.     ...  
  6.     temp=+2;    //這里本意是每次循環(huán),temp都自增2,但是卻將'+='寫(xiě)成了'=+',按照這種寫(xiě)法,每次循環(huán)都為temp賦值正數2,與本意相差甚遠  
  7. }  

2. 關(guān)于意想不到的死循環(huán)

  1.  unsigned char i;  
  2.   for(i=0;i<256;i++)  
  3.   {  
  4.          //something  
  5.   }  

        當我們用上述代碼想實(shí)現一個(gè)小循環(huán)時(shí),結果卻事與愿違,這其實(shí)是死循環(huán)的另一種寫(xiě)法,因為無(wú)符號變量i最大只有255,要命的是,編譯器并不會(huì )指出這個(gè)錯誤。

與之相類(lèi)似的代碼是:

  1.  unsigned char i;  
  2.   for(i=10;i>=0;i--)  
  3.   {  
  4.        //something  
  5.   }  

  這也是一個(gè)死循環(huán),你看出什么原因了嗎?無(wú)論i如何減,i都是大于等于0的。

        這就告訴我們對于每個(gè)變量類(lèi)型的取值范圍要由清醒的認識。值得注意的是相同的變量類(lèi)型對于不同的CPU構架和不同的編譯器會(huì )有不同的結果。比如int類(lèi)型在大多數16CPU構架中占用兩個(gè)字節,但在32CPU中卻往往占用4個(gè)字節;char類(lèi)型在絕大多數編譯器中都是有符號數,但在keil MDK中卻是無(wú)符號數,若是要在keil MDK下定義有符號char類(lèi)型變量,必須用signed顯式聲明。我曾讀過(guò)一本書(shū),其中有一句話(huà):“signed關(guān)鍵字也是很寬宏大量,你也可以完全當它不存在,在缺省狀態(tài)下,編譯器默認數據位signed類(lèi)型”,這句話(huà)便是有異議的,我們應該對自己所用的CPU構架以及編譯器熟練掌握。

3. 關(guān)于'='和'=='

  1. if(Value=0x01)  
  2. {  
  3.       //something  
  4. }  

      當我們判斷一個(gè)變量是否等于0x01時(shí),你是否也寫(xiě)過(guò)類(lèi)似上面的代碼?C語(yǔ)言的創(chuàng )造者認為賦值運算符"="出現的概率要遠遠大于等于運算符"==",因此,我們正常邏輯中的"等于"符號(=)C語(yǔ)言中成了賦值運算符,而C語(yǔ)言的"等于"運算符卻被兩個(gè)等于號(==)所代替。我之所以對這個(gè)事件耿耿于懷是因為我在大二的時(shí)候參加的C++二級上機考試,當我感覺(jué)很輕松的做完最后一道題后,卻發(fā)現運算的結果卻與邏輯相悖,經(jīng)過(guò)調試發(fā)現,有一個(gè)條件一直為真,我檢查了很多遍才發(fā)現出問(wèn)題的邏輯將等于運算符寫(xiě)成了賦值運算符。在if語(yǔ)句中給變量賦一個(gè)非零值,也難怪這個(gè)邏輯總是為真。

  編譯器同樣不對這個(gè)問(wèn)題做出指導性建議,值得一提的是,如果你在Keilif語(yǔ)句中使用了賦值運算符,編譯器會(huì )給出警告。

       避免這個(gè)問(wèn)題的一個(gè)很好的辦法是使用良好編程習慣,比如上面的代碼可寫(xiě)為:

  1. if(0x01==Value)  
  2. {  
  3.       //something  
  4. }  

        將常量值放到變量的前面,即使將等于運算符寫(xiě)成賦值運算符,編譯器也能產(chǎn)生一個(gè)語(yǔ)法錯誤,因為將一個(gè)變量賦值給一個(gè)常量是非法的。

4. error: #7: unrecognized token

       我在剛使用C語(yǔ)言以及Keil編譯器時(shí),對于這個(gè)編譯器錯誤,有很深的印象。出現這個(gè)編譯錯誤的典型代表是在敲代碼的時(shí)候輸入了中文標點(diǎn)??!

真是讓人感慨萬(wàn)分的錯誤!我們這些與硬件打交道的程序員,為模數電生,為PCB死,為Debug奮斗一輩子,吃需求的虧,上大小寫(xiě)的當,最后死在標點(diǎn)上??!

5. 關(guān)于字母'O'和數字'0',以及字母'l'和數字'1' ,在嵌入式編程中很容易和寄存器打交道,一個(gè)CPU如果有兩個(gè)相同模塊時(shí),這些模塊寄存器,往往使用數字0和數字1來(lái)區分模塊0和模塊1,比如,NXPARM7 串口模塊的兩個(gè)接收緩沖寄存器分別為:U0RBRU1RBR,要命的是在鍵盤(pán)上字母O和數字0相距的還那么近,你是否也有將上述寄存器寫(xiě)成UORBRUlRBR的經(jīng)歷,我是曾經(jīng)在這方面糾結過(guò)一次,好在編譯器能指出這個(gè)未定義的字符串。

6. sizeof()

        不知道有多少人和我曾經(jīng)一樣,將這個(gè)關(guān)鍵字認為是一個(gè)庫函數。

  1. int i,j;  
  2. j=sizeof(i); //對于這一句,當初壓根沒(méi)把它往關(guān)鍵字上想,這家伙偽裝的實(shí)在夠好。  

        既然提到它,不如多說(shuō)一下,sizeof在計算變量所占空間大小時(shí),括號可以省略,而計算類(lèi)型大小時(shí),不能省略。什么意思呢?還是上面的變量聲明,可以寫(xiě)成j=sizeof(i)也可以寫(xiě)成j=sizeof i,因為這是計算變量所占空間大??;可以寫(xiě)成j=sizeof(int),但不可以寫(xiě)成j=sizeof int,因為這是計算數據類(lèi)型大小。

         總體來(lái)說(shuō),關(guān)鍵字sizeof的具有一定的變態(tài)基礎的,在我還是小白的時(shí)候,曾經(jīng)為下面的一道題傷過(guò)腦袋:

下面代碼里,假設在32位系統下,個(gè)sizeof計算的結果分別是多少?

             int *p=NULL;

             sizeof(p)的值是:

             sizeof(*p)的值是:

             int a[100]

            sizeof(a)的值是:

            sizeof(a[100])的值是:

            sizeof(&a)的值是:

            sizeof(&a[0])的值是:

            int b[100];

            void fun(int b[100])

            {

                    sizeof(b);

            }

          sizeof(b)的值為:

7 關(guān)于數組越界

  1. int a[30];  
  2. for(i=30;i>0;i--)  
  3. {  
  4.     a[i]=something;  
  5. }  

這是個(gè)典型的數組越界例子,最近我同事的一個(gè)程序中便出現了。不知道有多少同學(xué)遇到或將要遇到數組越界問(wèn)題,即便你定義了30個(gè)數組a[30],你也不可以為a[30]賦值,因為下標為30的元素已經(jīng)越界了。所以說(shuō)數組下標定義的很奇特,它是從0開(kāi)始的。但當我們還是新手的時(shí)候,最容易忽視這一點(diǎn)。幸好現在的有些編譯器會(huì )對這個(gè)越界產(chǎn)生警告信息。

8. 關(guān)于宏

  1. #define MAX_TAST 4;  

        這個(gè)錯誤編譯器會(huì )指出的,即便這樣,相信很多同學(xué)在最初的時(shí)候也不會(huì )在第一時(shí)間發(fā)現這句代碼的最后多了一個(gè)分號。這個(gè)分號會(huì )導致一些編譯器報錯,因為宏定義的結尾并不需要分號。

        同樣與define有關(guān)的是這樣一句:#define  "config.h",我便吃過(guò)類(lèi)似暗虧,在編譯器的提示之下,看了幾遍才發(fā)現頭文件包含應該是#include "config.h"。

        既然提到#define,還是說(shuō)說(shuō)它需要注意的幾個(gè)點(diǎn),也是經(jīng)常在資料上被提及的。

       a.使用#define時(shí),括號一定要足夠。比如定義一個(gè)宏函數,求x的平方:                

  1. #define SQR(x)  x*x   .............. 1  

       或者這樣寫(xiě):               

  1. #define SQR(x)  (x)*(x) ............... 2  

       上面兩種都是有風(fēng)險的,對于第一種定義,SQR(10+1)就會(huì )得到和我們的設想不一致的結果;第二種SQR(5*3)*SQR(5*3)也會(huì )得到和我們設想不一致的結果,因此更安全的定義方法是: 

  1. #define SQR(x)  ((x)*(x))  

       b.使用#define的時(shí)候,,意空格的使用。比如下面的例子:                

  1. #define SQR  (x)  ((x)*(x))  

       這已經(jīng)不是SQR(x)函數了,編譯器會(huì )把認為定義了一個(gè)宏SQR,代表(x)  ((x)*(x)),因為SQR(x)之間有空格。這點(diǎn)需要注意。

      c.使用'#'在字符串中包含宏參數。比如下面的例子:               

  1. #define  SQR(x)  printf("The square of  x  is %d.\n",((x)*(x))")         

  1. 如果這樣使用宏<span style="font-family: 'Times New Roman'; ">:</span>             
  1.    SQR(8)  

       則輸出為:

                The square of  x  is 64.

        這個(gè)時(shí)候引號中的x被當做字符串來(lái)處理了,而不是一個(gè)可以被宏參數替換的符號.如果你想在字符中的x也被宏參數替換,可以這么來(lái)定義宏:       

  1. #define  SQR(x)  printf("The square of "#x" is %d.\n",((x)*(x))")  

       這樣得到的結果為:

               The square of 8 is 64.

        上面的這些例子,恐怕是網(wǎng)上隨處可見(jiàn)的,但真的會(huì )這么用卻有待考證。下面給出一個(gè)我自己遇到的不加括號產(chǎn)生錯誤的例子。在嵌入式編程中,遇到讀取IO端口某一位的電平狀態(tài)的場(chǎng)合是在平常不過(guò)的了,比如在NXP的ARM7中,讀取端口P0.11的電平狀態(tài)并判斷是否為高電平,代碼如下:

  1. #define READSDA       IO0PIN&(1<<11)            //定義宏,讀IO口p0.11的端口狀態(tài),但并未使用足夠多的括號  
  2.   
  3. //判斷p0.11端口是否為高電平,使用下述語(yǔ)句就是錯誤的:  
  4. if(READSDA==(1<<11))  
  5. {  
  6.      //是高電平,處理高電平的問(wèn)題  
  7. }  
編譯器在編譯后將宏帶入,原if語(yǔ)句變?yōu)椋?/span>

  1. if(IO0PIN&(1<<11) ==(1<<11))  
  2. {  
  3.     //是高電平,處理高電平的問(wèn)題  
  4. }  
這樣的話(huà),運算符'=='的優(yōu)先級是大于'&'的,從而IO0PIN&(1<<11) ==(1<<11))語(yǔ)句等效為IO0PIN&0x00000001,相當于判斷P0.1是否為高電平,與原意相差甚遠.

9. 數組和指針

        在32位系統下,

        定義一個(gè)數組:

  1. int a[10]={1,2,3,4,5,6,7,8,9,0};  

        定義一個(gè)指針:

  1. int *p;  

        那么,a、a[0]、&a、&a[0]各表示什么意思?

        那么,sizeof(a)、sizeof(a[0])、sizeof(&a)、sizeof(&a[0])的值各是什么

        如果,對指針p賦值:

       p=a;

       并且通過(guò)編譯器仿真,得知現在p等于a等于0x0000 0200,

       那么,a+1=?

                 &a+1=?

                 p+1=?

                p[2]=?

               *(p+2)=?

              *(a+2)=?

        再如果

  1. int *ptr=(int *)(&a+1);  

        那,*(ptr-1)=? 

        世上最曖昧、最糾纏不清的,莫過(guò)于數組名和指針。這一方面源于大學(xué)的教材并沒(méi)有重視這一塊,也源于教學(xué)時(shí)硬生生的將C語(yǔ)言和硬件分開(kāi)。一方面,教材和教這一門(mén)的老師在開(kāi)始時(shí)便向我們灌輸了“數組名和指針很像,可以等同”的思想;另一方面,在學(xué)C語(yǔ)言的時(shí)候,并沒(méi)有系統的學(xué)過(guò)計算機硬件(尋址、存儲、匯編),C語(yǔ)言是一個(gè)很接近硬件的高級語(yǔ)言,如果沒(méi)有處理器(包括單片機等微處理器)的基礎知識,會(huì )導致非常多的同學(xué)怎么都理解不透C語(yǔ)言的指針和數組。

        當我們定義一個(gè)數組int a[10]時(shí),編譯器會(huì )分配一塊內存,這塊內存的名字命名為a,這個(gè)a只是一個(gè)名字,只是方便編譯器和編程者使用,編譯器并不為這個(gè)名字分配空間來(lái)存儲它。我們可以用a[0]、a[1]來(lái)訪(fǎng)問(wèn)數組內的元素。a作為右值(位于等號的右邊)時(shí),表示的是數組第一個(gè)元素的地址(意義與&a[0]一樣,但&a[0]是一個(gè)指針變量,編譯器會(huì )為他分配空間,a卻不一樣,編譯器并不為它分配什么空間),而并非數組首地址,&a才表示數組的首地址。

        所以,第一個(gè)問(wèn)題,a是這個(gè)數組所在的內存的名字,當它為右值時(shí),表示數組首元素的地址,a[0]是數組的第一個(gè)元素,其值等于1,&a是整個(gè)數組的首地址,它是一個(gè)指針;&a[0]是數組首元素的地址,它的值和a做右值時(shí)一樣,但意義不同,因為&a[0]是一個(gè)指針,編譯器要為它分配存儲空間,但a卻不會(huì )被分配存儲空間,a也不是指針型變量。

        明白了上面那些,關(guān)于sizeof的計算也就不會(huì )困難了:

                 sizeof(a)=4*10=40,因為a代表的是整塊數組內存;

                 sizeof(a[0])=4,這相當于計算int的大小,在32位系統下,int4個(gè)字節。

                 sizeof(&a)sizeof(&a[0])都是計算指針變量的大小,在32位系統下,指針變量占4個(gè)字節。

        對于最后一個(gè)問(wèn)題,涉及到指針的加減。

       指針的加減中有一個(gè)重要的原則就是它的加減跟我們普通意義上的加減不是一個(gè)概念,它是按指針所指類(lèi)型的內存大小來(lái)進(jìn)行加減的。當我還是一個(gè)新手的時(shí)候,對于p++、p+1這類(lèi)指針運算的含義超出了我的意料之外,在上例中,若是p=0x0000 0200,那么p++運算之后的p值應該為0x0000 0204。有多少同學(xué),曾經(jīng)把它計算成0x0000 0201! 

        數組名a在做計算的時(shí)候表示數組首元素的地址,這時(shí)候a等于0x0000 0200,所以a+1等于0x0000 0200+4=0x0000 0204,因為一個(gè)int型在32位系統下占用4個(gè)字節。&a是整個(gè)數組的首地址,&a+1=0x0000 0200+4*10=0x0000 0228。

        其它的也都比較好理解,p+1=0x0000 0200+04=0x0000 0204、 p[2]=3、 *(p+2)=3、*(ptr-1)=0. 

10.  3/(-3)=?

       3%(-2)=?

    (-3)%2=?

         拋開(kāi)它是否有實(shí)際的意義,這個(gè)看似簡(jiǎn)單的語(yǔ)句,不知道有多少同學(xué)不確定結果到底是什么。

         其實(shí)大多數的編譯器遵循這樣一個(gè)規定:余數與被除數的正負號相同,被除數等于結果乘以除數加上余數。所以,以上的三個(gè)結果分別為-1、1、-1。

11. 指針數組與數組指針

       有一段時(shí)間,我怎么都不能區分指針數組和數組指針,就像下面的聲明:

  1. int * p1[10];  
  2. int (*p2)[10];  

        首先,要來(lái)解釋一下什么是指針數組,什么是數組指針:指針數組首先是一個(gè)數組,它的成員都是指針型變量;數組指針首先是一個(gè)指針,這個(gè)指針指向一個(gè)數組(它的值和數組名表示的值一樣,只是數組指針是一個(gè)變量,編譯器要為它分配存儲空間,但數組名類(lèi)似于一個(gè)常亮,是編譯器在編譯階段就確定好的一個(gè)值,編譯器不會(huì )為它分配存儲空間)。

        對于p1,由于中括號的優(yōu)先級(關(guān)于優(yōu)先級,后面會(huì )專(zhuān)門(mén)提起)是大于*的,所以p1首先與'[]'相結合,構成一個(gè)數組,在這個(gè)數組之前又有一個(gè)'*'運算符,說(shuō)明這是定義一個(gè)指針數組(int *a:定義一個(gè)指針a,這里可以將p1[10]替換成a,就不難理解了),數組的元素都是指向int型的指針。

         對于p2,'()'雖然與'[]'為同一優(yōu)先級,但卻是表達式結合方向從左到右結合的,所以編譯器會(huì )先處理(*p2),這是典型的定義一個(gè)指針,只不過(guò)這個(gè)指針指向一個(gè)包含10個(gè)int型數據的內存塊。為了加強理解,這里給出兩個(gè)相同原理的函數聲明:

                  void * p1(void);  ---------------------- 聲明1,定義一個(gè)返回值是void類(lèi)型指針的函數p1

                  void (*p2)(void); ----------------------- 聲明2,定義一個(gè)函數指針,該函數不返回任何值

       有了上面的鋪墊,現在定義一個(gè)高級C語(yǔ)言編程技巧中常用的函數指針數組應該很容易了吧!首先這是一個(gè)數組,數組的元素是指向一個(gè)函數的指針,以定義一個(gè)參數為空,返回值為int類(lèi)型的函數指針數組p1為例:

  1. int (*p1[5])(void);<span style="font-family: 'Times New Roman'; "> </span>  

   分析如下:

       定義一個(gè)返回值為int類(lèi)型的函數指針p1應該是:

  1. int (*p1)(void);  

        那么將這類(lèi)指針?lè )诺揭粋€(gè)數組中不正是我們需要的定義嗎,套用指針數組的定義方法,返回值為int類(lèi)型函數指針數組定義為:int (*p1[5])(void);

12 .運算符的優(yōu)先級

        C語(yǔ)言有32個(gè)關(guān)鍵字卻有44個(gè)運算符!運算符之間有固定的優(yōu)先級,雖然它們可以分成15類(lèi)優(yōu)先級,但如果讓一個(gè)程序員完全記住這些運算符之間的優(yōu)先級關(guān)系,怕是老手也是不容易的吧。如果你的程序只是語(yǔ)法錯誤,這類(lèi)錯誤是最容易解決的,編譯器就會(huì )幫你檢測出來(lái);如果是你自己的邏輯出現錯誤,那么根據運行結果仔細檢查一下代碼可能也不難發(fā)現;但若是你的邏輯正確卻記錯了運算符的優(yōu)先級關(guān)系,導致程序運行結果和你設想的不同,這種錯誤就很難查出了,因為在你的潛意識里,已經(jīng)把這種錯誤點(diǎn)當成理所當然不用關(guān)注的。

        請看下面一句代碼代表什么意思:

  1. *string ++;  

          由于*++但是單目運算符,優(yōu)先級相同,但結合方向卻是自右向左,那么*string++應該就是*string++),取出當前字符后將指針后移。不知道有沒(méi)有人把它認為是(*string)++,即取指針string所指向的對象,然后將該對象增1.  

        我曾經(jīng)在代碼中不止一次的出現過(guò)因為優(yōu)先級問(wèn)題而導致的程序邏輯錯誤,那個(gè)時(shí)候我并沒(méi)有完整的記過(guò)優(yōu)先級,二十使用了一種“偷巧”的方法:只是簡(jiǎn)單記住前幾級優(yōu)先級,其它自己沒(méi)把握的一律使用括號。這種方法我現在是不推薦的,一是因為大量的括號影響代碼閱讀和程序的簡(jiǎn)潔,二是總有時(shí)候我們稍微一松懈,就忘記了加括號,而后一種情況,正是很多人可能會(huì )遇到的。比如下面一句代碼,無(wú)符號8位變量ucTimeValue 中存放十進(jìn)制編碼的數據23,我想將十進(jìn)制編碼轉成16進(jìn)制編碼,代碼為:

  1. temp8=(ucTimeValue>>4)*10+ucTimeValue&0x0F;     //十進(jìn)制轉化為16進(jìn)制,但忽略了運算符'+'的優(yōu)先級是大于運算符'&'的  

        像這類(lèi)代碼編譯肯定可以通過(guò),但運行的結果卻出乎我的意料,而且由于我先入為主的錯誤思想,要在一大段代碼中發(fā)現這個(gè)錯誤著(zhù)實(shí)要花費一番功夫。 

再例如,如果我想判斷一個(gè)寄存器的某一位是否為零,假如是判斷寄存器IO0SETbit17是否為零,但代碼卻寫(xiě)成了這樣:

  1. if(IO0SET&(1<<17)==0)   

        這樣寫(xiě)其實(shí)是得不到正確的結果的,因為我忽略了"=="的優(yōu)先級是大于"&".按照上面的代碼分析:因為"=="的優(yōu)先級大于"&",所以程序先判斷(1<<17)是否等于0?發(fā)現這是不相等的,所以(1<<17)==0表達式的值為假,即為0,0(&)上任何一個(gè)數都是0,所以IO0SET&(1<<17))==0整個(gè)表達式的值永遠為0,這與原意相差甚遠。 

      按照原意,應該這樣寫(xiě):

  1. if((IO0SET&(1<<17)))==0)  

       其實(shí),運算符的優(yōu)先級是有一定的規律可循的,下面給出優(yōu)先級口訣(注:口訣來(lái)源于互聯(lián)網(wǎng))


優(yōu)先級口訣

       括號成員第一;                 括號運算符[]() 成員運算符.  ->

      全體單目第二;                  所有的單目運算符比如++ -- +(正) -(負) 指針運算*&

      乘除余三,加減四;             這個(gè)"余"是指取余運算即%

      移位五,關(guān)系六;              移位運算符:<< >> ,關(guān)系:> < >= <= 等

      等于(與)不等排第七;       即== !=

      位與異或和位或;             這幾個(gè)都是位運算: 位與(&)異或(^)位或(|) 

      "三分天下"八九十;  

      邏輯或跟與;                     邏輯運算符:|| 和 &&

      十二和十一;                     注意順序:優(yōu)先級(||)  底于 優(yōu)先級(&&) 

      條件高于賦值,                    三目運算符優(yōu)先級排到 13 位只比賦值運算符和","高

     逗號運算級最低!              逗號運算符優(yōu)先級最低

  

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Effective C++條款05解讀: 了解C++默默編寫(xiě)并調用哪些函數
C++數組隨筆
必須要注意的小細節:C語(yǔ)言結構體(struct)詳解~
C/C++中數組名作為函數形參
C語(yǔ)言結構體(struct)常見(jiàn)使用方法
C 的內存管理
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久