1. 程式人生 > >C進階2

C進階2

enum:可定義真正意義上的常量
sizeof:編譯器的內建指示符;用於計算型別或變數所佔的記憶體大小;
sizeof 的值在編譯期就已經確定,不參與程式的執行。
sizeof(var)或sizeof var;不是函式。
例:int var = 0;
int size = sizeof(var++);
printf(“var=%d,size = %d\n”,var,size);
結果為:0,4。var得不到執行。

例:

int f()
       {
	  printf("dddd\n");
	  return 0;
     	}	
	 int main ()
	{
	  int var = 0;
	  int size = sizeof (var++);
	  printf("var =%d,size =%d\n",var,size);
	  size = sizeof(f());
	  printf("size = %d\n",size);
	  return 0;
	}

執行結果並無打印出dddd,因sizeof非函式在程式編譯時就已經替換成了數值。
//-----------------------
typedef:用於給一個已經存在的資料型別重新命名;本質上不能產生新的型別;
其重新命名的型別:可以在typedef語句之後定義,不能被unsigned和signed修飾。
用法:typedef type new_name;
//------------------------------------------
註釋符號:\接續符,常用於巨集定義塊,減少一行的長度。
單引號和雙引號:“a”+1表示指標的運算;
char c = “string”;//編譯後字串“string”的記憶體地址被賦值給變數C;
記憶體地址佔用4個位元組,而變數C只佔用1個位元組,由於型別不同賦值後產生截斷。
//--------------------------------------------
!只認得0,見了0就返回1;碰見的值不是0時,結果為0。
在&&與||混合運算時,整個表示式被看作||表示式,從左向右先計算&&表示式,從左向右先計算&&表示式最後計算||表示式。
交換兩個變數的值採用異或操作。
邏輯運算||和位運算|兩回事。
四則運算>位運算>邏輯運算
//-----------------------------------------
●三目運算子:遵循隱式轉換規則。
a?b:c 當a的值為真時返回b的值,否則返回c的值;返回的是一個值不是變數。
(a<b ? a : b)=3;此式錯誤。*(a<b ? &a : &b)=3;此式正確。
●逗號表示式:連線語句,分號結束為一個語句。
//-------------------------------
編譯過程:預處理、編譯、彙編、連結。
預處理:處理註釋,巨集以及已經以#開頭的符號。
編譯:進行詞法分析,語法分析和語義分析等。
彙編:將彙編程式碼翻譯為機器指令的目標檔案。
連結是指將目標檔案最終連結為可執行程式;
靜態連結:目標檔案直接連結進入可執行程式
動態連結:在程式啟動後才動態載入目標檔案。
//------------------------------
可變引數:
push_test(const char *format,…)
…可變引數,format固定引數。
//-----------------------------
define字面量與const常量不同,它不佔記憶體。

#include <stdio.h>
#include "product.h"

    #if DEBUG
    #define LOG(s) printf("[%s:%d] %s\n", __FILE__, __LINE__, s)
    #else
    #define LOG(s) NULL
    #endif

   #if HIGH
  void f()
   {
    printf("This is the high level product!\n");
   }
   #else
  void f()
  {
  }
  #endif

int main()
{
   
    LOG("Enter main() ...");
    f();
    
    printf("1. Query Information.\n");
    printf("2. Record Information.\n");
    printf("3. Delete Information.\n");
    
    #if HIGH
    printf("4. High Level Query.\n");
    printf("5. Mannul Service.\n");
    printf("6. Exit.\n");
    #else
    printf("4. Exit.\n");
    #endif
    
    LOG("Exit main() ...");
    
    return 0;
}

//------------------------------------
條件編譯:
#if、#else、#endif被預編譯器初始,而if……else……語句被編譯器處理。
#erro用於生成一個編譯錯誤訊息,用法:#erro message;message不需要用雙引號包圍
#error預編譯器
#pragma back記憶體對齊
例子:

#include <stdio.h>
#pragma pack(8)
struct S1          // 對齊引數   偏移地址    大小
{
    short a;       //    2           0        2
    long b;        //    4           4        4
};

struct S2
{
    char c;        //    1           0         1
    struct S1 d;   //    4           4         8
    double e;      //    8           16        8
};

#pragma pack() // 預設為4
int main()
 {
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
    return 0;
 }

注:gcc不支援8位元組對齊。struct佔用的記憶體大小
第一個成員起始於0偏移處;每個成員按其型別大小和pack引數中較小的
一個進行對齊:偏移地址必須能被對齊引數整除;結構體成員的大小取其
內部長度最大的資料成員作為其大小。結構體長度必須為所有對齊引數的整數
倍。編譯器預設情況下按照四位元組對齊。
//---------------------------------------------
#運算子用於在預處理期將巨集引數轉換為字串
##運算子用於在預處理期粘連兩個識別符號
編譯器不知道#和##運算子的存在。

#define connect(a,b) a##b
int connect(a,1); //int a1;
a1=2;

 #include <stdio.h>
 #define STRUCT(type) typedef struct _tag_##type type;\
                     struct _tag_##type

STRUCT(Student)
{
    char* name;
    int id;
};

int main()
{
    
    Student s1;
    Student s2;
    
    s1.name = "s1";
    s1.id = 0;
    
    s2.name = "s2";
    s2.id = 1;
    
    printf("s1.name = %s\n", s1.name);
    printf("s1.id = %d\n", s1.id);
    printf("s2.name = %s\n", s2.name);
    printf("s2.id = %d\n", s2.id);

    return 0;
}

注:

typedef struct _tag_student student;
        struct _tag_student
        {};

//------------------------------------
利用指標交換變數:

#include<stdio.h>
int swap (int* a,int* b)
{
 int c = *a;
  *a = *b;
  *b = *c;
}
int main ()
{
   int aa = 1;
   int bb = 2;
   swap(&aa,&bb);
   printf("aa = %d\n,bb = %d\n",aa,bb);
   return 0;
}

注:const int* p; //p可變,p指向的內容不可變
int const* p; //p可變,p指向的內容不可變
int* const p; //p不可變,p指向的內容可變
const int* const p;//p和p指向的內容都不可變
//------------------------------
a[n]–(a+n)–(n+a)–n[a]
a與&a的區別:
a為陣列首元素的地址;&a為整個陣列的地址;a和&a的區別在於指標運算。
a+1—>(unsigned int)a+sizeof(a) 步長一個元素的大小
&a+1–>(unsigned int)(&a)+sizeof(
&a)步長一個數組的大小
(unsigned int)(&a)+sizeof(a)
題:int a[5]={1,2,3,4,5};
int* p1 =(int*)(&a+1);
int* p2 =(int*)((int)a+1);
int* p3 =(int*)(a+1);
問:p1[-1]:(p1-1)–>陣列地址加1–>結果為5
p2[0]: p2–>
注int a[5] 10002000300040005000
陣列a的地址值轉為int型加1,即地址值加1,指向1後面的0,取四個位元組。
結果為0x02000000即…
p3[1]:p3指向a+1,
(p3+1)為3.
//----------------------------------
陣列作為函式引數時,編譯器將其編譯成為對應的指標:
void f(int a[]);<–>void f(int
a);
void f(int a[5]);<–>void f(int* a);