找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3482|回复: 6

【C语言】函数的玄机

[复制链接]
发表于 2016-7-6 03:31:49 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
This is an (most of Chinese Cpl teacher) untold story of the function in plain C.
C语言的函数,我们并不陌生。
要学习生物体,就得先学习生命最基础的表现形式——细胞。
同样,因为C是面向过程的,函数就是程序的细胞。我们学习C语言,总错过不了她。
细胞有细胞膜、细胞壁opt、细胞质、细胞器、细胞核。
那么,函数有啥内容值得学习?
首先我们要明确函数书写的两大基本概念:函数的声明(declaration)和函数的定义(definition)
函数的声明确定了函数的形态,特征。这个形态特征决定函数名称(一个合法的C标识符),和函数参数列表。
我们声明一个函数:
int add(a, b); // 声明后面必加分号!
另一种声明方式,在这种声明方式中,我们明确了参数列表内各参数的类型:
int add(int a, int b); // 注意要加分号!
我们将上面那个函数声明成外部的:
extern int add(int a, int b); // 这里也要加分号!
再来看函数的定义:函数的声明确定了函数执行什么样的运算过程。
我们定义那个声明好的add函数:
int add(int a, int b)
{
        return a + b;
}
同时,函数的定义也可以与函数的声明写在一起:
extern int add(a, b) // 还没明确说明参数a,b的类型呢!
int a; // 此时我们也可以事后加以说明。
int b; // 要有分号哦!
{
        return a + b;
}
那么,大家有没有被我一套大道理、官话讲晕掉了呢?
好了!In summarize:
如果函数在定义处之前被调用(Invoke)那么,这个函数需要在调用处(invocation)之前被声明。
换句话讲,我让张三做一件叫做add的事情(这是声明)。
到底张三怎样做add这件事呢?我告诉他,把我给你的a加上我给你的b,然后还给我(这些是定义)。

如果我先说:张三哪,你去做add(a, b);
等到张三拿到我给他的a b(实际参数):x = add (1, 2); 时候就问了:领导,add这件事,我怎么去实施啊?
当然我是一个负责任的领导,会这样说:笨呐!自己动动脑子啊!养你这么多年,钞票都喂猪啦?(如果我真的这样说,编译器会给我使脸色:找不到函数add的参照。)
我会耐心说道:
int add(int a, int b) // add这件事呢,你首先拿好我给你的俩宝贝,最后你要还我一个int类型的宝贝。
{
        return a + b; // 具体来讲,你要把宝贝a和宝贝b加起来,还给我,就是这样啦。
}
这种情况的代码如下(完整的可执行的):
  1. #include <stdio.h>
  2. int add(int, int);
  3. int main()
  4. {
  5.     printf("%d\n", add(1,1));
  6.     return 0;
  7. }
  8. int add(int a, int b)
  9. {
  10.     return a + b;
  11. }
复制代码


换一种情况:我一口气说:
张三你去做add这件事,等你拿到俩宝贝,最后你要还我一个int型的宝贝,你需要把宝贝a和宝贝b加起来还给我,do you get it?
这种情况就是声明定义在一起,那么写成如下代码(完整的可执行的):
  1. #include <stdio.h>
  2. add(a, b) // 没有声明返回类型,默认int类型!
  3. int a;
  4. int b;
  5. {
  6.     return a + b;
  7. }

  8. main()
  9. {
  10.     printf("%d\n", add(1, 2));
  11. 4  return 0;
  12. }
复制代码


最后要注意:正确的做法是在声明的时候加上inline(内联)和extern(外部)或者static(静态)关键字,而定义的时候不加inline和extern或者static关键字。

接下来,我们再谈一个比较高大上的内容,
那就是,不定参数函数(Variadic functions)。
典型的不定参数函数就是众所周知的printf函数和scanf函数。
我们来看看printf怎么使用的:int a = 1, b = 2, c = 3; printf("%d,%d,%d", a, b, c);
再来看看printf怎么声明的:printf(const char * restrict, ...);
printf函数的第一个参数restrict实际是一个参数检查列表,这个参数指向的字符串内让打印多少个int就得打印多少个int。
在实际的程序编写过程中,你想让她打印几个int就写几个%d,写1000个%d都行,printf就傻傻地打印1000个int。
这是一项超级棒的语法啊!我认为其好玩性仅次于vb的可选函数参数和函数参数默认值语法:
Declare Function Bar(a As Integer, Optional b As Integer = 1) As Integer
想象一下我们如何利用它?
对了,做一个求和函数:
大概是这样:sum(1,2,3)得出6; sum(1,2,3,4,5)得出15.
代码如下:
  1. #include <stdio.h>
  2. #include <stdarg.h>     // 包含允许使用不定参函数的头文件。
  3. int sum(int count, ...) // 参数count代表要求几个数的和。不确定的参数列表使用 “...” 代替。
  4. {
  5.         va_list var; // 使用va_list宏定义一个变化参数
  6.         int s = 0;   // 定义s存放累加的结果。
  7.         va_start(var, count); // 用va_start宏将检查列表装入var,表示要检查一共count个参数。
  8.                 while (count)
  9.                 {
  10.                         s += va_arg(var, int); // 每次使用va_arg宏将下一个参数取出,转换成为int类型,并且累加。
  11.                         count--;
  12.                 }
  13.         va_end(var); // 加上va_end宏表示一直要累加到最后一个。
  14.         return s;
  15. }
  16. int main()
  17. {
  18.         // 计算1加到10的和减去1加到5的和他们俩的差。
  19.         printf("%d\n", sum(10 ,1,2,3,4,5,6,7,8,9,10) - sum(5 ,1,2,3,4,5));
  20.         return 0;
  21. }
复制代码

关于Variadic functions的更详细信息,这里有俩个外部链接可供大家参考:
1.wiki上的关于stdarg.h头文件的说明:https://en.wikipedia.org/wiki/Stdarg.h
2.本站的ISO C Standard白皮书(E文原版):https://www.0xaa55.com/forum.php?mod=viewthread&tid=1759

本帖被以下淘专辑推荐:

回复

使用道具 举报

发表于 2016-7-6 11:32:15 | 显示全部楼层

      
期待了这么久的C文章,这次文章读来不那么过瘾。         
             其实我要求也不高,建议用汉字的时候,不要夹带英文,显得不伦不类,英语差看了半天都不知道单词意思。         
             在c里面是函数,在vb里面是过程。标准库里面没有现成的过程,就需要我们自己定义函数,它有自己的结构(和细胞一样),         
             使用也很简单,文章已说明。变参听说过,唯独又说得太少!

        
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2016-7-6 12:50:51 | 显示全部楼层


好!接受建议,下次加以修正。
英文的话,我认为提一下declaration,和definition比较重要。
因为毕竟还是建议去查看英文原版资料。
有些中文还是不能完全翻译到位。
比如Variadic functions这个我也不知官方标准翻译是啥。很多中文教科书都没有。

另外一个例子:argument parameter attribute这三个没有固定意思,都可以解释为“参数”,但是要结合上下文,这就很头疼了。
stack overflow翻译为“栈溢出”,但是如果人家还提到stack underflow
overflow就得翻译为“上溢”,underflow翻译为“下溢”。瞬间成“矢量”了。
回复 赞! 靠!

使用道具 举报

发表于 2016-7-7 16:49:13 | 显示全部楼层
标题不是全角的方括号看得我好不爽
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2016-7-7 23:41:40 | 显示全部楼层
0xAA55 发表于 2016-7-7 16:49
标题不是全角的方括号看得我好不爽

已经修改,话说osx死活打不出“【】”
回复 赞! 靠!

使用道具 举报

发表于 2016-7-9 00:34:11 | 显示全部楼层

1、C里面的函数,有时候也可以说成是“过程”,比如没有返回值的函数(比如void xxx();)
2、VB里的过程一般是没有返回值的,比如Sub xxx()而VB里也有函数,那些有返回值,并且返回值很有用的就是函数,比如Sqr()
3、我也想吐槽中英文混合。。那些词其实我也不知道意思,以我的风格我可能会写个中日文混合的帖子呢~~
回复 赞! 靠!

使用道具 举报

发表于 2018-1-14 14:44:58 | 显示全部楼层
可以可以!!
回复

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-25 06:20 , Processed in 0.033122 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表