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

C語言筆記(一),c語言筆記

編輯:關於C語言

C語言筆記(一),c語言筆記


笑話一枚:
程序員 A:“哥們兒,最近手頭緊,借點錢?”
程序員 B:“成啊,要多少?”
程序員 A:“一千行不?”
程序員 B:“咱倆誰跟誰!給你湊個整,1024,拿去吧。”

========================= 我 是 分 割 線 =========================

前言


C語言允許直接訪問物理地址,可以直接對硬件進行操作,非常適合開發內核和硬件驅動。

書上看來一句話:普通人用 C 語言在 3 年之下,一般來說,還沒掌握 C 語言;

        5 年之下,一般來說還沒熟悉 C 語言;10 年之下,談不上精通。

學習一門語言最基本的還是要多碼碼,多調試,必要的時候可以用小黃鴨調試法。

多思考,遇到問題自己先嘗試深入研究和解決。

下面的筆記來自《C語言深度解剖》

 

變量


定義、聲明最重要的區別:定義創建了對象並為這個對象分配了內存,聲明沒有分配內存。

 

一般的變量使用駝峰命名法(CamelCase),加上必要的前後綴。
所有宏定義、枚舉常數、只讀變量全用大寫字母命名,用下劃線分割單詞。

 

c語言有4種存儲類型:auto, extern, register, static,定義變量的時候只能指定其中的一種類型。
而變量分配在內存存儲空間的有:BSS區、數據區、棧區、堆區。

進程在內存中的結構

  • 代碼區:存放CPU執行的機器指令,代碼區是可共享,並且是只讀的。
  • BSS區:存放的是未初始化的全局變量和靜態變量。
  • 數據區:存放已初始化的全局變量、靜態變量(全局和局部)、常量數據。
  • 棧區:由編譯器自動分配釋放,存放函數的參數值、返回值和局部變量,在程序運行過程中實時分配和釋放,棧區由操作系統自動管理,無須程序員手動管理。
  • 堆區:由malloc()函數分配的內存塊,使用free()函數釋放內存,堆的申請釋放工作由程序員控制,容易產生內存洩漏。

也有變量不在內存中:register 變量可能不存放在內存中,所以不能用取址運算符“&”來獲取 register 變量的地址。

 

static的2個作用

第一個作用:修飾變量。靜態全局變量和靜態局部變量,都存在內存的靜態區。
   靜態全局變量,作用域僅限於變量被定義的文件中,其他文件即使用 extern 聲明也沒法使用他。
   靜態局部變量,在函數體裡面定義的,就只能在這個函數裡用了,同一個文檔中的其他函數也用不了。
第二個作用:修飾函數。不是指存儲方式,而是指對函數的作用域僅局限於本文件(所以又稱內部函數)。
好處是:不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它文件中的函數同名。

 

sizeof關鍵字

int i=0;
A),sizeof(int); B),sizeof(i); C),sizeof int; D),sizeof i;

這裡只有選項C是錯誤的,因為 sizeof 在計算變量所占空間大小時,括號可以省略,而計算類型大小時括號不能省略。
還有就是 sizeof 不怕地址越界,它只計算變量類型占空間大小,不會去訪問變量的地址,也就不清楚人家存不存在了。

 

signed、unsigned 關鍵字

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


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 中。

 

什麼時候要使用 volatile ?

如果 i 是一個寄存器變量或者表示一個端口數據或者是多個線程的共享數據,就容易出錯,所以說 volatile 可以保證對特殊地址的穩定訪問。

 

大小端模式


3.確認當前系統的存儲模式?

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 處開始的。

5.在 x86 系統下,以下程序輸出的值為多少?

#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;
}

 

結構體struct


6.下面2段代碼有什麼區別?

//代碼(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


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

函數編寫的一些注意:

  • 保護性編程
  • 縮進量統一使用4個字符
  • 在一個函數體內,變量定義與函數語句之間要加空行
  • 邏揖上密切相關的語句之間不加空行,其它地方應加空行分隔
  • 復雜的函數中,在分支語句,循環語句結束之後需要適當的注釋,方便區分各分支或循環體  //end“for(condition)”
  • 使用 assert 宏做函數入口校驗 assert(NULL != p);
  • 遞歸的深度太大可能出現錯誤(比如棧溢出)
  • return 語句不可返回指向“棧內存”的“指針”,因為該內存在函數體結束時被自動銷毀

 

文件


文件命名:模塊名縮寫 + 小寫字母名字

文件頭部說明

/************************************************************************
 * 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

 

之後的打算:


  • 閱讀《現代方法》(第2版)中關於預處理的部分
  • 學習arm匯編
  • 從匯編語言的層次理解C語言,姚新顏先生的《C語言:標准與實現》《C/C++深層探索》,關於X86匯編

 

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