C语言深度剖析笔记(2)

1.C语言的预处理。
#define
#undef
A),#define ENG_PATH E:/English/listen_to_this
这条预处理有几点需要注意:首先,如果对于"ENG_PATH"这样的引用,不会把ENG_PATH解释成后面的话;接着是有些

编译器需要把/改成//
B),#define BSC //
#define BMC /*
#define EMC */
因为注释先于预处理指令被处理,当这两行被展开成//或者/* */的时候,已经注释了掉了EMC
C),
#define X 2
#define Y X*2
#undef X
#define X 3
此时Y的值应该为6
#ifdef//#ifndef
程序段1
#else
程序段2
#endif
如果标识符已经被#define命令定义过,则对程序段1进行编译;否则对程序段2编译。
#error error-message//注意这里的message不用双引号包围。
#line //没搞明白有啥作用,改变当前的行数和文件名称
#pragma message()//里面放信息,当用了许多宏控制源码版本的时候,有可能忘记没有正确设置的宏,此时我们可

以用这条指令在编译的时候进行检查。
#ifdef _X86
#pragram message("_X86 macro activated!")
#endif
#pragma once//能保证头文件被编译一次。
#pragma warning(disable:4507 34;once:4385;error:164)//不显示4507和34号浸膏信息;4385号只警告一次把164

号警告信息作为一个错误
#pragma warning(push,n)保存所有警告信息的现有警告状态,并且把全局警告等级设定为n
#pragma comment()//将指令一个注释记录放入一个对象文件或可执行文件中。
#pragma comment(lib,"user32.lib")//将user32.lib库文件加入到本工程中。
#pragma comment(linker,"/include:_mySymbol")//将一个链接选项放入目标文件中,你可以使用这个指令来代替由

命令行传入的或者开发环境中设置的连接选项,你可以指定/include选项来强制包含某个对象。
2.C程序中的内存对齐。
struct TestStruct1{
 char c1;
 short s;
 char c2;
 int i;
};//大小12
struct TestStruct2{
 char c1;
 char c2;
 short s;
 int i;
};//大小8
也可以使用#pragma pack(n),改变对齐方式,按照N个字节对齐。
#pragma pack(8)
struct TestStruct3{
 char a;
 long b;
};//a是1字节(此时指定默认1字节对齐),和指定8字节比较,按1字节对齐;b是4字节有大的就按大的对齐,所以默

认就4字节对齐。所以sizeof(TestStruct4)应该为8;
struct TestStruct4{
 char c;
 TestStruct3 d;
 long long e;
};//c本来按1字节对齐,看到d中最大的数据是b,所以就按4字节对齐。d存入后正好是12字节(剩下4字节无法存入e)

,而默认是8字节,所以再加4字节存入e。
#pragma pack()

 


3.指针与数组
如何将数值存储到指定的内存地址?
int *p=(int *)0x12ff7c;
//*p=0x100;给P赋值,p是上面的值
*p=NULL;//你会认为只是p所指的内存值变为0x00000000,而p本身没变。但事实上p变为0x00000000了
p=NULL;

如果你把前面加入
int i=10;
int *p=(int *)0x12ff7c;
*p=NULL;//这样的话p本身没有变,而p指向内存的值变成0了
p=NULL;

如果再加入j,编程:
int i=10;
int j=100;
int *p=(int *)0x12ff7c;
*p=NULL;
p=NULL;
这样的话j的地址刚好是0x12ff7c,这就和上面的一样了,可是把int j=100删了,又编程最开始的了。
这个可能是VC6中的BUG

int a[5];
数组是分配一块空间,把这块空间命名为a,大小为5*sizeof(int)
sizeof(a[0]);相当于sizeof(int)
sizeof(a[5]);虽然没有此元素,但是sizeof并没有真正访问a[5],而是用元素类型来确定此值。
指针就是指针,在32位系统下,永远4字节,可以指向任何地方。
数组就是数组,其大小和类型个数有关。

假设a的首地址0x0012ff6c
a//a在这里代表数组首地址相当于a[0]的地址,为0x0012ff6c
&a//代表数组首地址,值0x0012ff6c
a+1//值是0x0012ff6c+1*sizeof(int)


char a[100];//file1
extern char *a;//file2
这样可以吗,在文件1中当作数组,而在2中当作指针可以吗?
为什么extern char a[]和extern char a[100]等价,因为只是声明,不分配空间,所以编译器无需知道这个数组由

多少元素。但是当声明为extern char *a时,编译器当它为一个指针变量,应该分配4个字节的空间。
在文件1中,编译器知道a是一个数组,但是在文件2中编译器不知道这点。虽然a实际大小100,但在2中编译器认为a

只由4个byte。由于编译器会把存在指针变量中的任何数据当作地址处理,所以,如果需要访问这些字符类型数据,

我们必须先从指针变量a中取出地址。
所以编译器按照a为地址,取出数组a[0],a[1],a[2],a[3]取出4byte当作地址。把数据存放倒这个4byte组成的数据为

地址的地方。
同样char *p="abcedfg";
extern char p[];

char a[5]={'a','b','c','d'};
char (*p3)[5]=&a;//因为&a是数组首地址,而p3就是一个存储首地址指针的数组(指针数组),所以赋值正确
char (*p4)[5]=a;//给出警告,因为a是第一个元素的地址

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值