程序中的函数声明和函数定义在哪里?为什么?
在C语言中,程序从main()函数开始,其他函数只有被main函数调用才能运行。
当编译好的可执行程序从shell解释器运行时,主函数将被shell启动并开始运行。
C语言的函数在使用时要经历三个步骤:声明、定义和调用。
函数声明就是给出函数的原型,让程序员知道如何给函数传递参数,如何接收返回值,让编译器知道如何检查代码类型。主函数的声明如下:
int main();
它的返回值是int类型,不需要参数。
printf()函数的声明如下:int printf(const char* fmt,...);
它的返回值是int类型,第一个参数是格式字符串,然后后面可以跟变量参数。
函数声明的语法是:
返回值类型的函数名(参数类型0,参数变量0,参数类型1,参数变量1);
如果有多个参数,请用逗号分隔。每个参数都有一个类型和一个变量名,声明时可以省略参数的变量名。最后,用分号结束声明语句。
如果不想让人看到函数的源代码,可以只提供一个语句和编译后的文件,别人只能看到汇编代码(笑)。C语言的这种设计有利于知识产权的保护。
函数定义是指函数体在声明后用不带分号的大括号表示,函数的具体代码写在大括号里面。
上图中的main()函数是定义,printf()函数是声明。
定义,它实现了函数的内容。函数不能多次定义,否则编译器不知道使用哪个定义的代码。
但是函数可以多次声明,只要声明是相同的并且不矛盾。
只要放上两个大括号{},就定义了一个函数。空实现也是一种实现。可以先占这个位置,以后再填具体的功能码。也就是先给出整个方案的框架,然后再填充细节。
函数实现后,必须调用它才能运行。
除了main函数由shell启动之外,其他所有函数都应该由main函数直接或间接调用。
当一个函数运行时,实际上有一个从主函数到它的调用链。
函数调用的语法是:
函数名(自变量变量0,自变量变量1);
如果有多个参数,请用逗号分隔。如果希望接收函数调用的返回值,可以使用变量来接收:
返回值变量=函数名(自变量变量0,自变量变量1);
返回值变量的类型要和函数的返回值类型一致,使用前要声明。
对于有返回值的函数,没有必要接收它的返回值。例如,尽管printf()有一个int类型的返回值来指示打印了多少个字符,但它通常不会被接收。
所以C语言的入口代码是printf(“hello world \ n”);
而不是int ret = printf(" hello world \ n ");
函数名在C语言中属于标识。
标识符的命名规则是以下划线或大小写字母开头,然后可以是数字、字母、下划线(但不能是运算符或其他特殊符号)。
它们在代码中用于表示变量名、结构类型名、函数名或用于goto的标签。
基本类型的类型名被定义为关键字,不能再用作标识符。
结构
int a;
int b;
} s;
是一个标识符,指示结构类型。
a是标识符,表示结构的成员变量a。
S是一个标识符,代表变量S,它的类型是结构类型S。
函数名也是标识符,所以函数名也要以下划线或大小写字母开头,不能是关键字、运算符或其他特殊符号。
0123,这不可能是函数名,C语言中以0开头的数是八进制数。
0x123,也不能是函数名,以0x开头的数是十六进制的数16。
Main,可以作为函数名,是主函数。整个程序中只能有一个,不能作为普通函数的名字。
__schedule以下划线开头,可以用作函数名。
但是,以两个下划线开头的函数大多是Linux系统或C库的函数。普通函数最好不要这样命名。
Char,这不能是函数名,是字符型的关键字。
+,也做不到,是加法的运算符。
CreateWindowEx,可以作为函数名,看起来是典型的匈牙利风格,微软代码(笑)。这个函数是一个在windows系统上创建窗口的API。
匈牙利风格的代码是微软的一种流行风格。函数名以一个或多个英文单词命名,每个单词的首字母大写,其他字母小写。
但是Linux代码(包括第三方软件)仍然保持了古代C代码的下划线风格,字母全部小写,单词用下划线隔开,使用的缩写更多。
有时缩写后面只剩下几个字母,直接组成一个新词作为函数名。
例如,在Linux上启动一个新程序的函数executable()是一个缩写词。
要执行的英文单词叫execute,windows上的可执行程序叫exe文件,就是这个单词的前三个字母,Linux也选择了这三个字母。
三个字母cve来自主函数的完整参数列表:
int main(int argc,char* argv[],char * envp);
main函数的完整声明是这样的,int main()是简化版。
第一个参数argc表示传递给main函数的参数数量。作为命令行参数传递。Arg是参数argument的缩写,c是count,是参数的个数。
Argv是参数字符串数组(传递给main函数),v指vector。
Envp是环境变量环境路径的路径。
因此,启动main的系统调用称为executable(),而不是StartProgram()。
后者虽然明显好理解,但是字母多,系统调用的API也不是一眼就能看出来启动进程的(汗)。
回到开头,main()函数是由Linux上的executable () API启动的,然后由main函数直接或间接调用其他函数。
未被main函数调用(直接或间接)的函数将不会运行。
上面显示的代码将只打印add,因为main只调用add()函数,而不调用sub()函数。
这个简单的代码,只有这三个函数,sub()没有被调用过。