一 概述
二 类型
三 语句
四 函数
五 数据
六 内存
七 代码
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
1. 定义
函数是指令组织和最小重用单元,完成一个相对独立的任务。
每个函数仅被定义一次,但可在多处声明。函数被调用前,必须先声明(前置声明)。声明中的参数名可选。实际上对编译器没有意义,只是可增加使用者友好度。
- 函数不是第一类对象(first-class)。
- 不支持重载(overload)。
- 不支持默认参数。
- 不支持多返回值。
- 不支持嵌套。(ISO C 不支持,GCC 扩展支持)
- 不支持匿名函数,不支持闭包。
return_type func_name(params) { code block }
修饰符
extern
: 默认。外链接,其他模块可用。static
: 内链接,仅当前模块可用。inline
: 和 static 配合,建议编译器内联。(用于定义)_Noreturn
: 告知编译器,该函数不再返回。
_Noreturn
表示调用该函数后不再返回调用处,编译器会优化掉后续代码。如果该函数没有执行流终止行为(比如
exit
、longjmp
),则编译器会警告。
_Noreturn static void test () { exit(0); } int main (void) { test(); // 不再生成后续指令。 printf("hello, world!\n"); return 0; }
参数
使用逗号分隔多个参数。如没有参数,可为空或 void。不能合并多个相同类型的参数。
int add (int x, y) { ^ unknown type name 'y'
参数被当做函数局部变量对待。可使用 register 声明,但可能被编译器忽略。
参数总是值传递。可通过复制指针传递引用,或用二级指针实现传出参数(out)。
位于函数参数列表里的称作形参( parameter ),传递给函数调用的称作实参( argument )。
形参在调用时分配存储空间,其作用域为函数块;实参会被复制成形参,它可以是变量、常量或表达式。
所以,默认对形参的修改不影响实参。(注意区别指针间接修改)
void test (int **x) { int *p = malloc(sizeof(int)); *p = 100; *x = p; } int main (void) { int x = 10; int *p = &x; printf("%p\n", p); test(&p); printf("%p\n", p); free((void*)p); return 0; }
虽然生成代码相同,但 func()
表示未指定参数数量和类型, func(void)
则明确表示没有参数。
void test() { test(100); return; }
如参数列表是
test()
,代码可编译,编译器不会检查调用参数是否正确。而
test(void)
,会明确引发一个编译错误。
数组类型参数方括号内常量表达式实际会被忽略。
但使用
type[]
要比type*
更明确表明要接收一个数组,而不仅仅是个指针。虽然两者行为相同,但对于使用者更友好。
void test (int x[8]) { printf("%p\n", x); } int main (void) { test((int[3]){1, 2, 3}); return 0; }
返回值
返回值可以是 void,或函数和数组之外的其他类型。
可返回堆内存指针(malloc),返回函数和数组指针。
typedef int data_t[3]; data_t test () ^~~~ error: 'test' declared as function returning an array {
typedef void (func_t)(); func_t test () ^~~~ error: 'test' declared as function returning a function {
返回局部变量指针存在风险。
int* test () { int x = 100; return &x; ^~ warning: function returns address of local variable }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论