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