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);

猜你喜欢

转载自blog.csdn.net/weixin_42068537/article/details/84310945