首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言進階筆記(二):註釋細節、位運算、花括號、自增減、除模、優先級、預處理、main 參數、陣列指標

     編輯:關於C語言

註釋細節

  • 編譯器以空格替換註釋,早於預處理執行。
  • /* ... */ 不可嵌套。
  • / 和 * 間無空格即視為註釋開始:y = x/*p; → y = x 後被註釋。
  • \ 行接續符:剔除換行符,前後無空格。亦作轉義字符開頭。

位運算符

// 交換兩變量無需暫存
a ^= b; b ^= a; a ^= b;

// 優先級陷阱
0x01 << 2 + 3;  // + 優先於 <<,等價 0x01 << 5 = 32

// 32 位系統移位限制
// 移位位數不能 ≥ 數據位寬(32),不能 < 0(否則未定義行為)

// 有符號數右移:符號位跟隨移動
// 正數高位補 0;負數高位補 0/1 視編譯器(Turbo C 等補 1)

// 常用位操作宏
#define SETBIT(x,y)   ((x) |= (y))
#define CLRBIT(x,y)   ((x) &= ~(y))
#define TOGLBIT(x,y)  ((x) ^= (y))
#define TESTBIT(x,y)  ((x) & (y))

// 按位號操作
#define SETBIT(x,y)   ((x) |= 1 << (y))
#define CLRBIT(x,y)   ((x) &= ~(1 << (y)))

花括號作用

打包初始化列表:char a[10] = {"abcde"};

自增減 ++/--

// 未定義行為:同一序列點多次修改同一變量
i = 3; (++i)+(++i)+(++i);  // TCC:15, VC6:16, GCC:18 → 不要這樣寫

// 後綴 ++/--:在遇到 , 或 ; 結束當前計算單元後才自增減
i = 3; (i++)+(i++)+(i++);  // 依編譯器不同

// 逗號表達式:左求值、右求值,整體值為最右表達式值
j = (i++, i++, i++);  // j=2, i=3
j = (++i, ++i, ++i);  // j=3, i=3

/ 與 % 運算

C99 規定商向零截斷,餘數符號與被除數同號:

 3 /  2 =  1    3 %  2 =  1
-3 /  2 = -1   -3 %  2 = -1
 3 / -2 = -1    3 % -2 =  1
-3 / -2 =  1   -3 % -2 = -1

優先級補充

  • . [] () 高於 *(解引用)
  • == != 高於位運算
  • == != 高於賦值
  • 算術高於移位

預處理

非 C 語言核心,屬編譯器功能。

標準預定義宏

  • __LINE__、__FILE__、__DATE__、__TIME__、__STDC__

宏定義細節

  • #define EMPTY 和 # define EMPTY 皆合法。
  • 調用宏函數時宏名與參數間空格被忽略;定義時空格有效。
  • #error 強制編譯報錯:#error message。
  • #line 修改行號/文件名:#line 100 "test.c"。
  • #pragma 編譯器指令。
  • # 字串化,## 符號連接。

斷言 assert 實現

#if !defined(NDEBUG)
#define assert(p) if(!(p)){fprintf(stderr,\
 "Assertion failed: %s, file %s, line %d\n", #p, __FILE__, __LINE__); abort();}
#else
#define assert(p)
#endif

main 函數參數

int main(void)                    // 無參
int main(int argc, char *argv[])  // 有參
int main(int argc, char **argv)   // 等價
  • argc:參數總數(含程序名)。
  • argv[0]:程序名。
  • argv[i]:第 i 參數。

例:./a.out Love Live ! → argc=4,argv[1]="Love" 等。

陣列

  • int a[5]; 編譯器分配連續記憶體,a 為首地址別名,不可修改。
  • &a[0] 首元素地址;&a 整個陣列地址(值相同,類型義不同)。
  • a 作右值 = &a[0](首元素地址);a 不能作左值。

陣列指標

int main() {
    char a[5] = {'A','B','C','D'};
    char (*p3)[5] = &a;   // 類型完全匹配
    char (*p4)[5] = a;    // 右值為 char*,隱式轉換(值相同)
    // p3+1 指向下一個 5-char 陣列,偏移 5 bytes
    // p4+1 同理(因類型相同)
}

指標基礎

野指標成因

  1. 定義未初始化。
  2. free/delete 後未置 NULL(僅釋放記憶體,指標本身仍存)。

安全用法

char *p = NULL;      // 定義即初始化
// 使用...
free(p);
p = NULL;            // 用後即置空

指標作函數參數

一維陣列作參數,編譯器自動轉為首元素指標:void f(int a[]) ≡ void f(int *a)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved