笑話一枚:
程序員 A:“哥們兒,最近手頭緊,借點錢?”
程序員 B:“成啊,要多少?”
程序員 A:“一千行不?”
程序員 B:“咱倆誰跟誰!給你湊個整,1024,拿去吧。”
========================= 我 是 分 割 線 =========================
C語言允許直接訪問物理地址,可以直接對硬件進行操作,非常適合開發內核和硬件驅動。
書上看來一句話:普通人用 C 語言在 3 年之下,一般來說,還沒掌握 C 語言;
5 年之下,一般來說還沒熟悉 C 語言;10 年之下,談不上精通。
學習一門語言最基本的還是要多碼碼,多調試,必要的時候可以用小黃鴨調試法。
多思考,遇到問題自己先嘗試深入研究和解決。
下面的筆記來自《C語言深度解剖》
定義、聲明最重要的區別:定義創建了對象並為這個對象分配了內存,聲明沒有分配內存。
一般的變量使用駝峰命名法(CamelCase),加上必要的前後綴。
所有宏定義、枚舉常數、只讀變量全用大寫字母命名,用下劃線分割單詞。
c語言有4種存儲類型:auto, extern, register, static,定義變量的時候只能指定其中的一種類型。
而變量分配在內存存儲空間的有:BSS區、數據區、棧區、堆區。
也有變量不在內存中:register 變量可能不存放在內存中,所以不能用取址運算符“&”來獲取 register 變量的地址。
第一個作用:修飾變量。靜態全局變量和靜態局部變量,都存在內存的靜態區。
靜態全局變量,作用域僅限於變量被定義的文件中,其他文件即使用 extern 聲明也沒法使用他。
靜態局部變量,在函數體裡面定義的,就只能在這個函數裡用了,同一個文檔中的其他函數也用不了。
第二個作用:修飾函數。不是指存儲方式,而是指對函數的作用域僅局限於本文件(所以又稱內部函數)。
好處是:不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它文件中的函數同名。
int i=0;
A),sizeof(int); B),sizeof(i); C),sizeof int; D),sizeof i;
這裡只有選項C是錯誤的,因為 sizeof 在計算變量所占空間大小時,括號可以省略,而計算類型大小時括號不能省略。
還有就是 sizeof 不怕地址越界,它只計算變量類型占空間大小,不會去訪問變量的地址,也就不清楚人家存不存在了。
1.下面的代碼輸出是什麼?為什麼?
void foo(viod) { unsigned int a = 6; int b = -20; (a+b>6)?puts(">6"):puts("<=6"); }
2.下面的代碼的結果是多少?為什麼?
intmain() { char a[1000]; inti; for(i=0; i<1000; i++) { a[i] = -1-i; } printf("%d",strlen(a)); return 0; }
void 的字面意思是“空類型”,void *則為“空類型指針”,void *可以指向任何類型的數據。
任何類型的指針都可以直接賦值給 void *,無需進行強制類型轉換:
void *p1;
int *p2;
p1 = p2;
case 後面的值只能是整型或字符型的常量或常量表達式。
定義 const 只讀變量,具有不可變性。const 修飾的仍然是變量,只不過是只讀屬性罷了,不能當作常量使用。
const 修飾符也可以修飾函數的參數,當不希望這個參數值被函數體內意外改變時使用。
const的作用:節省空間,避免不必要的內存分配,同時提高效率
編譯器通常不為普通 const 只讀變量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的值,沒有了存儲與讀內存的操作,使得它的效率也很高。
volatile修飾的變量,編譯器對訪問該變量的代碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。
先看看下面的例子:
inti=10;
intj = i;//(1)語句
intk = i;//(2)語句
這時候編譯器對代碼進行優化,因為在(1)、(2)兩條語句中,i 沒有被用作左值(沒有被賦值)。這時候編譯器認為 i 的值沒有發生改變,所以在(1)語句時從內存中取出 i 的值賦給 j 之後,這個值並沒有被丟掉,而是在(2)語句時繼續用這個值給 k 賦值。編譯器不會生成出匯編代碼重新從內存裡取 i 的值,這樣提高了效率。
但要注意:(1)、(2)語句之間 i 沒有被用作左值才行。
再看另一個例子:
volatile inti=10;
intj = i;//(3)語句
intk = i;//(4)語句
volatile 關鍵字告訴編譯器 i 是隨時可能發生變化的,每次使用它的時候必須從內存中取出 i 的值,因而編譯器生成的匯編代碼會重新從 i 的地址處讀取數據放在 k 中。
如果 i 是一個寄存器變量或者表示一個端口數據或者是多個線程的共享數據,就容易出錯,所以說 volatile 可以保證對特殊地址的穩定訪問。
int checkSystem{ union check { int i; char ch; }c; c.i = 1; return(c.ch == 1); }
若處理器是 Big_endian 的,則返回 0;若是 Little_endian 的,則返回 1。
大端模式(Big_endian) :字數據的 高字節 存儲在 低地址中,而字數據的 低字節 則存放在 高地址中。
小端模式(Little_endian):字數據的 高字節 存儲在 高地址中,而字數據的 低字節 則存放在 低地址中。
union { int i; char a[2]; }*p,u; p = &u; p->a[0] = 0x39; p->a[1] = 0x38;
union 型的成員的存取都是相對於該聯合體基地址的偏移量為 0 處開始的。
#include <stdio.h> int main(void) { int a[5] = {1,2,3,4,5}; int *ptr1 = (int *)(&a + 1); int *ptr2 = (int *)((int)a + 1); printf("%x,%x\n",ptr1[-1],*ptr2); return 0; }
//代碼(1) structTestStruct1 { char c1; shorts; char c2; inti; }; //代碼(2) structTestStruct2 { char c1; char c2; shorts; inti; };
sizeof(TestStruct1)的值為 12
sizeof(TestStruct2)的值為 8
字,雙字,和四字在自然邊界上不需要在內存中對齊。(對字,雙字,和四字來說,自然邊界分別是偶數地址,可以被 4 整除的地址,和可以被 8 整除的地址。)無論如何,為了提高程序的性能,數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的內存,處理器需要作兩次內存訪問;然而,對齊的內存訪問僅需要一次訪問。
可以利用#pragma pack()來改變編譯器的默認對齊方式:
#pragma pack(n) //n=1,2,4,8,16…
enum Color { GREEN = 1, RED, //2 BLUE, //3 GREEN_RED = 10, GREEN_BLUE //11 }ColorVal;
// 功 能: 改變緩沖區大小 // 參 數: nNewSize 緩沖區新長度 // 返回值: 緩沖區當前長度 // 說 明: 保持原信息內容不變
/************************************************************************ * Function Name : nucFindThread * Create Date : 2000/01/07 * Author/Corporation : your name/your company name * * Description : Find a proper thread in thread array. * If it’s a new then search an empty. * * Param : ThreadNo : someParam description * ThreadStatus : someParam description * * Return Code : Return Code description,eg: ERROR_Fail: not find a thread ERROR_SUCCEED: found * * Global Variable : DISP_wuiSegmentAppID * File Static Variable : naucThreadNo * Function Static Variable : None * *------------------------------------------------------------------------ * Revision History * No. Date Revised by Item Description * V0.5 2008/01/07 your name … … ************************************************************************/ static unsigned char nucFindThread(unsigned char ThreadNo,unsigned char ThreadStatus) { // TODO:... } //Blank Line
文件命名:模塊名縮寫 + 小寫字母名字
/************************************************************************ * File Name : FN_FileName.c/ FN_FileName.h * Copyright : 2003-2008 XXXX Corporation,All Rights Reserved. * Module Name : DrawEngine/Display * * CPU : ARM7 * RTOS : Tron * * Create Date : 2008/10/01 * Author/Corporation : WhoAmI/yourcompany name * * AbstractDescription : Place some descriptionhere. * *-----------------------Revision History-------------------------------- * No Version Date Revised By Item Description * 1 V0.95 08.05.18 WhoAmI abcdefghijklm WhatUDo * ************************************************************************/ #ifndef __FN_FILENAME_H #define __FN_FILENAME_H #endif // Debug Switch Section // Include File Section // Macro Define Section // Structure Define Section // Prototype Declare Section // Global Variable Declare Section // File Static Variable Define Section // Function Define Section