LEMON源码分析笔记——分割源码
五千多行代码集于一个文件,这不是什么明智之举。根据源码中的提示,可以编程一个分割程序。
分割程序的工作是,识别出文件名,并把用它创建文件,写入相应内容。在处理过程序,记录头文件。在识别出源文件时,把在其前的头文件#include进去。理论上这样做是可行的。因为源文件所需的定义或声明一定在其前的头文件中包含了。而源文件之间没有什么瓜葛。但LEMON源代码并不是想象中的那么规范。有许多地方要改。
l 调用了其它文件的静态函数。msort.c实现的内部函数msort被action.c中调用;action.c实现的内部函数action_sort在report.c中调用。
l 调用其它源文件的静态变量。main.c中定义的内部变量int nDefine,char** szDefine在parse.c中引用。
l 源文件中定义宏与结构体。action.c中定义了的宏acttab_size,acttab_yyaction,acttab_lookahead会在report.c中引用。action.c中还定义了acttab结构体,而此结构在report.c中需要引用。
为消除警告而采取的修改
警告 | 修改 |
buildshift中调用了没有声明的Action_add | 在action.h中添加Acion_add声明 |
Configlist中调用的msort的第三个参数与configcmp不匹配 | 强制类型转换(int (*)(const char*,const char*)) |
main 中调用的qsort的第四个参数与Symbolcmp类型不匹配 | 强制类型转换(int (__cdecl *)(const void *,const void *)) |
VSdeprecate警告 | 在global.h中添加#pragma warning(disable 4996) |
ReportTable的调用的acttab_action,acttab_alloc,acttab_insert没有事先声明 | 在acttab.h中添加声明 |
append_str中n+sizeof(zInt)*2+used >= alloced警告“signed/unsigned mismatch” | n+(int)sizeof(zInt)*2+used >= alloced |
警告NEXT宏类型转换:“'type cast' : pointer truncation from 'char *' to 'unsigned long'” | 工程属性->C/C++->常规->【检测64位可移植性问题】选否 |
小结:
1. 两源程序中出现同名结构体,以本文件的结构体定义为准。Extern过来的变量,其值直接覆盖在本文件结构体上。
/*file1.c*/
struct node
{
char ch1;
char ch2;
};
struct node n = {1, 0};
/*file2.c*/
struct node
{
int data;
};
/*在file2.c中,n只量使用data域,其值被,0由低到高填充,故为*/
2. 只要函数在声明或定义的开头加上了static那么,它就是一个静态函数。只能够在本文件内被访问。
3. C语言允许函数在没有声明之前就发生调用。包括库函数
void main()
{
printf("hello world!/n");
fopen("test.data","wb");
}
但assert函数不行,因为这是一个宏
#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
4. 头文件中通常会包含内部函数与全局函数的声明。内部函数不向外提供调用,那么为什么要包括在头文件中呢?原因是,为其所在源文件内部对其的调用,提供事先声明。头文件的内部函数声明,不是为别的源文件而声的,而是为该内部函数所在的源文件声的。当然其中的全局函数也是出于这个原因,但全局函数还得为别源文件提供事先声明。
问题是如果将这样的头文件包含在未定义其中内部函数的源文件中,结果会是怎样的呢?分四种情况:
| 调用 | 定义 |
内部函数 | declared but not defined | ok |
全局函数 | ok | 找到一个或多个多重定义的符号 |
5. 头文件不参加编译。如果头文件未被include进源文件中,编译器不会检查其语法的。