一、代码变量的内存分布
查看别人的对代码内存的了解:资料1-变量的探索;内存分布的探索详细;C语言的5大内存;
看了很多帖子,我发现我要买一本《程序员的自我修养》
了解了一些elf的相关命令
readelf xxx.out -S #产看elf文件的文件
readelf -X .text #一16进制查看某个段的信息
readeld xxx.out -a #很详细的查看xxx.out的各种信息的总览
size xxx.out #查看xxx.out的三个段的信息
引用别人的代码:适合自己见解的代码引用
#include <stdio.h>
const int g_A = 10; //代码段
int g_B = 20; //数据段
static int g_C = 30; //数据段
static int g_D; //BSS段
int g_E; //BSS段
char *p1; //BSS段
void main( )
{
int local_A; //栈
static int local_C = 0; //数据段
static int local_D; //数据段
char *p3 = "123456"; //123456在代码段,p3在栈上
p1 = (char *)malloc( 10 ); //堆,分配得来得10字节的区域在堆区
strcpy( p1, "123456" ); //123456{post.content}放在常量区,编译器可能会将它与p3所指向 的"123456"优化成一块
printf("\n");
printf( "代码段,全局初始化变量, 只读const, g_A, addr:0x%08x\n", &g_A);
printf("\n");
printf( "数据段,全局变量, 初始化 g_B, addr:0x%08x\n", &g_B);
printf( "数据段,静态全局变量, 初始化, g_C, addr:0x%08x\n", &g_C);
printf("\n");
printf( "BSS段, 全局变量, 未初始化 g_E, addr:0x%08x\n", &g_E, g_E );
printf( "BSS段, 静态全局变量, 未初始化, g_D, addr:0x%08x\n", &g_D );
printf( "BSS段, 静态局部变量, 初始化, local_C, addr:0x%08x\n", &local_C);
printf( "BSS段, 静态局部变量, 未初始化, local_D, addr:0x%08x\n", &local_D);
printf("\n");
printf( "栈, 局部变量, local_A, addr:0x%08x\n", &local_A );
printf("\n");
printf( "堆, malloc分配内存, p1, addr:0x%08x\n", p1 );
}
内存变量的总结
二、变参函数的了解
臭不要脸的我剽窃的帖子:参考的帖子1;变参函数的应用探索;
va_list、va_start、va_arg、va_end的相关资料:函数的标准解答;
示例代码
#include<stdio.h>
#include<string.h>
#include<stdarg.h> //va_list、va_start、va_arg和va_end的头文件
/*
va_list类型用于声明一个变量,该变量依次引用各参数,在函数minprintf中,将该变了成为ap,意思是参数
指针,在使用ap前,该宏必须先被调用一次,参数表至少包含一个有名参数,va_start将最后一个有名参数
做为起点,每次调用,va_arg,该参数返回一个参数,并将ap指向下一个参数,va_arg使用一个类型名来决定
返回对象的类型,指针移动的步长,最后必须在函数返回之前调用va_end,以便完成一些必要的清理工作。
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数的值
#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效
*/
void minprintf(char *fmt,...)
{
va_list ap; //va_list表示可变参数列表类型,实际上就是一个char指针
char *p,*sval;
double dval;
int ival;
va_start(ap,fmt); //sizeof(fmt)=8 fmt=0x7fff3ae4b3b8 ap=0x7fff3ae4b3e0 两个字符的指针 获取字符串的首地址\
我猜想,这一句是fmt的首地址赋给ap 现在还在疑惑
for(p=fmt;*p;p++)
{
if(*p!='%')
{
putchar(*p);
continue;
}
switch (*++p)
{
case 'd':
ival=va_arg(ap,int); //获取int类型的参数
printf("%d",ival);
break;
case 'f':
dval=va_arg(ap,double);
printf("%f",dval);
break;
case 's':
for(sval=va_arg(ap,char *);*sval;sval++) //获得字符串的首地址
{
putchar(*sval);
}
break;
default :
putchar(*p);
break;
}
}
va_end(ap);
}
int sum(int m,...)
{
va_list ap;//依次指向每个无名参数
va_start(ap,m);//将ap指向第一个无名参数
int sum=0;
while(m--)
{
sum+=va_arg(ap,int);
}
va_end(ap);//结束时候的清理工作
return sum;
}
int main(int argc,char *argv[])
{
minprintf("ajsdsajksdvasda %d %s %f \n",10,"asa",20.1);
printf("%d\n",sum(3,10,20,32));
return 0;
}
结果:
三、inline关键字(内联函数)的应用
查略的相关资料:较全的inline资料;嵌软的inline学习
编译器的相关:GCC的安装;
gcc flag.c -L ./ #添加头文件的地址
头文件
#ifndef __A_H__
#define __A_H__
#include<stdio.h>
//函数定义为inline即:内联函数
inline char* dbtest(int a);
#endif
源文件
#include "A.h"
char* dbtest(int a)
{
return (a % 2 > 0) ? "奇" : "偶";
}
int main()
{
int i = 0;
for (i=1; i < 10; i++)
{
printf("i:%d 奇偶性:%s \n", i, dbtest(i));
}
}
运行现象:
这个inline的关键字和#define、const等的比较。