关于指针问题

来源:互联网 发布:mysql 事务实现原理 编辑:程序博客网 时间:2024/06/02 06:40
如果想更加了解,想从事底层开发需要看(关于内核,驱动和嵌入式)《链接器和加载器》一书。



auto:自动变量,默认的存储类别 例如当我们定义一个变量时,如果不加修饰
就代表了他是自动变量的类型(auto)。
register:寄存器变量,其类别的变量会被优先分配到寄存器,通常作为循环因子的变量会被分配到寄存器里。
extern:外部变量(全局变量):该关键字可以扩展全局变量的作用域,扩展的范围是从使用extern开始到该文件结束。
static:静态局部变量,这种数据存储在数据段上。




在C语言中,一个指针变量同样可以指向一个数组。如下所示:
  int(*p)[10];
表示p是一个指针,指向一个数组对象,该数组是一个拥有10个整形元素
的数组。
因此当p+1时,p移动的字节数应该等于p所指的数组对象的字节数。
也就是跳到整个指针数组的最后一个字节的下一个字节。
#include<stdio.h>
int main(void)
{
  int a[5]={1,2,3,4,5};
  int (*p)[5];
  int *ptr;
  p=&a;
  ptr=(int *)(p+1);//将数组指针转换为整形的指针。
  printf("the result is:%d\n",*(ptr-1));
  return 0;  
}
结果:
the result is:5
分析一下结果的原因。p=&a,因此p是数组指针,其类型为int(*)[5]。
而指针加1要根据指针的类型加上一定的值,而不同类型的指针加1后
增加的大小是不同的。
ptr实际是a[5],但是ptr与(p+1)类型是不一样的一个是整型指针,而另一个是
数组指针,经过强制类型转换后,ptr只会减去sizeof(int)。这时ptr已经指向了数组中的第4个元素。




修改指针变量本身时,应当将该指针变量的地址作为参数。
#include<stdio.h>
#include<stdlib.h>
void alter(int **p)
{
  int *q;
  q=(int *)malloc(sizeof(int));
  *q=100;
  *p=q;
}
int main()
{
  int a;
  int *p;
  a=10;
  p=&a;
  printf("0x%x,*p %d\n",p,*p);
  alter(&p);
  printf("0x%x,*p %d\n",p,*p);
 return 0;
}
结果:
 *p=10;
 *p=100;
指针变量的值被修改了。




在c语言中的指针可以指向整型,字符型或者结构体类型等
也就是用 整型,字符型和结构体定义一个指针。




函数的指针 
函数名代表了函数代码的首地址
函数指针的声明
函数的返回类型 (*指针变量名)(函数的参数列表);
声明一个函数指针,例如
int (*p)(int,int)
声明一个指针变量p其返回值得类型是int ,其参数的类型也是两个整型变量。
例如函数 int fun(int ,int )
p=fun;
(*p)(int,int)等价于fun(int,int)了。
   


函数指针数组
函数返回值 (*数组名[元素的个数])(参数列表);
例如:
    int (*a[2])(int,int);






限定修饰符const
const限制符是c语言中的一个关键字。该关键字所修饰的变量是不可更改的:
例如:
int const a=1;
const int a=1;
也就是说用const修饰符对变量进行赋值时具有唯一的一次赋值机会。
也就是说经过const修饰之后该变量的值不能再次的进行修改了。


关于内存对齐问题:
为了高速处理数据,现代数据引入了内存对齐。32位体系结构
默认是4个字节对齐。
内存对齐是以空间来换取时间的方法。






               inline函数和带参数的宏的区别


               inline函数                      带参数的宏
              
展开机制:  在编译的时候展开,因此      在预处理时展开,因此#define  
            inline关键字是一个编译      关键字是一个预处理关键字 
            关键字        


参数类型    inline函数是一种函数,     不会检查参数类型,只是做简单的
检查:      会进行严格的参数类型       字符串替换,因此在使用带参数的
            检查                       宏的时候会有一些副作用。编写程 
                                       序时需要人为预防。


是否允许    不允许出现复杂语句,       对此不作要求。宏只做字符串替换
有复杂语    如果出现复杂语句,         操作,而不了解语句的意义,因此 
句:        该函数将不会被展开。       不会有这种限制
            例如递归,大型循环
            等。




是否一定   不一定,是否需要展开        一定,只要使用了宏就可以保证其
被展开     由编译器决定                被忠实的展开




GCC编译一个c语言需要经过一下4个步骤:
1.将c语言源程序预处理,生成.i文件。
2.预处理后的.i文件编译称为汇编语言,生成.s文件。
3.将汇编语言文件经过汇编,生成目标文件.o文件。
4.将各个模块的.o文件链接起来生成一个可执行程序文件。
  


静态库的生成:
静态库生生成的是.a库 
ar rcs 静态库名 目标文件1 目标文件2 .......
gcc main.c -l静态库名 -o 目标文件(-l是用来指定静态库了)
参数rcs的含义,r:是把列表中的目标文件加入到静态库里。
c:若指定的静态库不存在,则创建库文件。
s:最后更新静态库文件的索引,使之包含新加入目标文件文件的内容。


动态库的生成:
动态库生成的是.so库
命令:gcc -shared -fPIC -o shared_lib.so shared_lib.c
使用 gcc main.c ./shared_lib.so -o app1
    ./app1




初始化数据段(.data):通常也称为数据段,它包含程序中明确给定的初值
的全局变量和静态变量:
例如:int max=100; 或者static int count=10;
初始化数据段在编译器的时候确定该段的大小,在程序运行过程中该段的大小
不能发生变化。


非初始化数据段(.bss):存储在这个段中的数据通常是没有明确给定初值的全局变量和静态变量。例如: int max;(全局变量)或者 static int count:
这个段的内容往往不存储在外存上,而是在程序运行时由内核将段中的数据初始化成0 或者NULL(对于指针)。


*bss段中的内容并不作为程序文件的一部分,而被保存到外存中
原创粉丝点击