代码想转换成.exe文件,需要经过几个步骤:
    替换    ->为了可读性或方便,使用了一些宏定义;在编译前,会有一个工具将宏定义的符号替换成相应的值;
    编译    ->将代码转成二进制文件;
    连接    ->代码中可能用到了别人写的程序,连接就是将别人的程序复制一份放到自己的程序中;
 
1.宏定义
1)无参数的宏定义
无参数的宏定义的一般形式为:# define 标识符 字符序列
例如:
注意:
    1、只作字符序列的替换工作,不作任何语法的检查                                                
    2、如果宏定义不当,错误要到预处理之后的编译阶段才能发现    
 
2)带参数的宏定义
带参数宏定义:#define 标识符(参数表)字符序列
 
例如:
# define MAX(A,B) ((A) > (B)?(A):(B))                    
代码 x= MAX( p, q)将被替换成 y=((p) >(q)?(p):(q)
好处是:如果直接定义一个相同功能的函数,在执行是必须给函数分配内存空间,而宏定义是替换代码,不需要给子函数分配空间;
 
注意:
    1、宏名标识符与左圆括号之间不允许有空白符,应紧接在一起.否则会被当做不带参数的宏括号后面的参数被当做该符号的值                                                
    2、宏与函数的区别:函数分配额外的堆栈空间,而宏只是替换.                                                
    3、为了避免出错,宏定义中给形参加上括号.                                                
    4、末尾不需要分号.                                                
    5、define可以替代多行的代码,记得后面加 \                                                
    #define MALLOC(n,type)\                        
        ((type*)malloc((n)*sizeof(type)))    
 
2.头文件
头文件的使用:                
步骤一:                
void Function()                
{                
    printf(“Hello World!”);            
}                
int main(int argc, char* argv[])                
{                
    Function();            
    return 0;            
}        
可以执行                
                
如果换成:                
int main(int argc, char* argv[])                
{                
    Function();            
    return 0;            
}                
void Function()                
{                
    printf(“Hello World!”);            
}          
不能执行!                
                
解决办法:新增头文件(.h),在.h文件中对函数进行说明.                
如:                
.c文件:                .h文件
                
void Function()                void Function();
{                
    printf(“Hello World!”);            
}                
                
在如何函数的Cpp文件中包含.h文件    
 
3.头文件重复包含的问题
例如:3个头文件
如果此时有个文件同时包含了x.h和y.h会出问题。                    
如:                    
#include “stdafx.h”                    
#include “X.h”                    
#include “Y.h”                    
                    
int main(int argc, char* argv[])                    
{                    
                    
    return 0;                
}
 
解决方案:    
#if !defined(ZZZ)    
#define ZZZ    
    
struct Student    
{    
    int level;
};    
    
#endif    
这句话的意思可以这样去理解,如果ZZZ已经存在了,就不在声明.        
ZZZ相当于一个编号,越复杂越好,唯一的
 
4.内存分配与释放
申请内存时有时知道需要的大小;例如int x;
有时无法确定需要申请的内存大小;
这时需要动态申请内存;
 
可以用malloc函数来申请内存;
void *malloc(size_t size)
使用malloc:
int* ptr;//声明指针   
                 
//在堆中申请内存,分配128个int                    
ptr = (int *)malloc(sizeof(int)*128);                    
                    
//无论申请的空间大小 一定要进行校验 判断是否申请成功                    
if(ptr == NULL)                    
{                    
    return 0;                
}                    
                    
//初始化分配的内存空间                    
memset(ptr,0,sizeof(int)*128);                    
                    
//使用。。。                    
*(ptr) = 1;                    
                    
//使用完毕 释放申请的堆空间                    
free(ptr);                    
                    
//将指针设置为NULL                    
ptr = NULL;            
 
注意事项:                                
    1、使用sizeof(类型)*n 来定义申请内存的大小                                
    2、malloc返回类型为void*类型 需要强制转换;
        malloc返回值为void*是因为不能确定调用者需要的具体类型;
        void*不能加减整数,因为去掉一个*后的宽度不确定;而指针类型运算时需要该宽度;                                
    3、无论申请的内存有多小 一定要判断是否申请成功                                
    4、申请完空间后要记得初始化.                                
    5、使用完一定要是否申请的空间.                                
    6、将指针的值设置为NULL.    
 
关于堆中的内存:
    用malloc申请的内存是堆中分配的;
    全局变量在全局变量区,用不用都在那里,不需要考虑内存释放的问题;
    局部变量在栈区,也是无论是否使用都已经分配了,同样不需要考虑释放;
    堆中的内存是现用现取的,malloc之后会告诉系统这块内存我用了,系统就不让别人用了;
        如果不释放则会造成内存泄露,也就是即使申请内存的程序停止运行了,内存依然被占用;
        所以一定要告诉操作系统这块内存不用了;用free方法释放内存;
 
5.文件操作函数
fopen    ->打开文件
fseek    ->设置指针指向文件的什么位置
ftell    ->获取指针偏离文件头部的距离
fread    ->将文件读到缓冲区
fclose    ->关闭文件
 
1)fopen
FILE *fopen( const char *path, const char *mode );
函数说明:
1.path就是指定打开文件的路径,可以是相对路径,也可以绝对路径。mode代表打开文件的方式
2.fopen打开成功,返回FILE的有效地址,失败返回NULL.
3.fopen返回的指针是不能自己计算的,一定是要给C语言文件操作的库函数操作的
 
“r” :以只读方式打开文件,该文件必须存在。
“w” :打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
“a” :以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
“r+” :以可读写方式打开文件,该文件必须存在。
“w+” :打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
“a+”:以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
“rb” :只读打开一个二进制文件,只允许读数据。
“wb” :只写打开或建立一个二进制文件,只允许写数据。
“ab” :追加打开一个二进制文件,并在文件末尾写数据。
“rb+” :读写打开一个二进制文件,允许读写数据,文件必须存在。
“wb+” :读写打开或建立一个二进制文件,允许读和写。
“ab+” :读写打开一个二进制文件,允许读,或在文件末追加数据。
“rt” :只读打开一个文本文件,只允许读数据。
“wt” :只写打开或建立一个文本文件,只允许写数据。
“at” :追加打开一个文本文件,并在文件末尾写数据。
“rt+” :读写打开一个文本文件,允许读和写。
“wt+” :读写打开或建立一个文本文件,允许读写。
“at+” :读写打开一个文本文件,允许读,或在文件末追加数据。
 
2)fseek和ftell获取文件大小
1】fseek用来设置文件指针位置
函数原型: int fseek(FILE *fp,long offset,int origin);
函数功能:把fp的文件读写位置指针移到指定的位置.
参数: fp:文件指针;
    offset:相对于origin规定的偏移位置量;
    origin:表示指针移动的起始位置,可设置为以下三种情况之一: 
        SEEK_SET: 文件开始位置 
        SEEK_CUR: 文件当前位置 
        SEEK_END: 文件结束位置
例如:fseek(fp,20,SEEK_SET); 意思是把fp文件读写位置指针从文件开始后移20个字节.
 
2】ftell函数是用来获取文件的当前读写位置;
函数原型: long ftell(FILE *fp)
函数功能:得到流式文件的当前读写位置,其返回值是当前读写位置偏离文件头部的字节数.
例如:ban=ftell(fp); 是获取fp指定的文件的当前读写位置,并将其值传给变量ban.
 
3】获取文件大小
可以用fseek函数把位置指针移到文件尾,再用ftell函数获得这时位置指针距文件头的字节数,这个字节数就是文件的长度.
fseek(fp,0,SEEK_END);
int len = ftell(fp);
 
3)将文件读到内存缓冲区
LPVOID ReadPEFile(LPSTR lpszFile)
{
    FILE *pFile =NULL;
    //DWORD fileSize=0;
    LPVOID pFileBuffer=NULL;
    //打开文件
    pFile=fopen(lpszFile,”rb”);
    if (!pFile)
    {
        printf(“无法打开EXE文件!”);
        return NULL;
    }
    //读取文件大小
    fseek(pFile,0,SEEK_END);
    fileSize=ftell(pFile);
    fseek(pFile,0,SEEK_SET);
    //分配缓冲区
    pFileBuffer=malloc(fileSize);
    if (!pFileBuffer)
    {
        printf(“分配空间失败!”);
        fclose(pFile);
        return NULL;
    }
    //将文件数据读取到缓冲区
    size_t n=fread(pFileBuffer,fileSize,1,pFile);
    if(!n)
    {
        printf(“读取数据失败!”);
        free(pFileBuffer);
        fclose(pFile);
        return NULL;
    }
    //关闭文件
    fclose(pFile);
    return pFileBuffer;
}
 
 
 

版权声明:本文为ShiningArmor原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/ShiningArmor/p/11673180.html