-
Notifications
You must be signed in to change notification settings - Fork 25
/
ch03s01.html
16 lines (15 loc) · 10.9 KB
/
ch03s01.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>1. 数学函数</title><link rel="stylesheet" href="styles.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Linux C编程一站式学习" /><link rel="up" href="ch03.html" title="第 3 章 简单函数" /><link rel="prev" href="ch03.html" title="第 3 章 简单函数" /><link rel="next" href="ch03s02.html" title="2. 自定义函数" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">1. 数学函数</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03.html">上一页</a> </td><th width="60%" align="center">第 3 章 简单函数</th><td width="20%" align="right"> <a accesskey="n" href="ch03s02.html">下一页</a></td></tr></table><hr /></div><div class="sect1" lang="zh-cn" xml:lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id2712397"></a>1. 数学函数</h2></div></div></div><p>在数学中我们用过sin和ln这样的函数,例如sin(π/2)=1,ln1=0等等,在C语言中也可以使用这些函数(ln函数在C标准库中叫做<code class="literal">log</code>):</p><div class="example"><a id="id2711787"></a><p class="title"><b>例 3.1. 在C语言中使用数学函数</b></p><div class="example-contents"><pre class="programlisting">#include <math.h>
#include <stdio.h>
int main(void)
{
double pi = 3.1416;
printf("sin(pi/2)=%f\nln1=%f\n", sin(pi/2), log(1.0));
return 0;
}</pre></div></div><br class="example-break" /><p>编译运行这个程序,结果如下:</p><pre class="screen">$ gcc main.c -lm
$ ./a.out
sin(pi/2)=1.000000
ln1=0.000000</pre><p>在数学中写一个函数有时候可以省略括号,而C语言要求一定要加上括号,例如<code class="literal">log(1.0)</code>。在C语言的术语中,<code class="literal">1.0</code>是参数(Argument),<code class="literal">log</code>是函数(Function)<a id="id2712436" class="indexterm"></a>,<code class="literal">log(1.0)</code>是函数调用(Function Call)<a id="id2712449" class="indexterm"></a>。<code class="literal">sin(pi/2)</code>和<code class="literal">log(1.0)</code>这两个函数调用在我们的<code class="literal">printf</code>语句中处于什么位置呢?在上一章讲过,这应该是写表达式的位置。因此函数调用也是一种表达式,这个表达式由函数调用运算符(()括号)和两个操作数组成,操作数<code class="literal">log</code>是一个函数名(Function Designator)<a id="id2712482" class="indexterm"></a>,它的类型是一种函数类型(Function Type)<a id="id2712489" class="indexterm"></a>,操作数<code class="literal">1.0</code>是<code class="literal">double</code>型的。<code class="literal">log(1.0)</code>这个表达式的值就是对数运算的结果,也是<code class="literal">double</code>型的,在C语言中函数调用表达式的值称为函数的返回值(Return Value)<a id="id2712519" class="indexterm"></a>。总结一下我们新学的语法规则:</p><div class="literallayout"><p>表达式 → 函数名<br />
表达式 → 表达式(参数列表)<br />
参数列表 → 表达式, 表达式, ...</p></div><p>现在我们可以完全理解<code class="literal">printf</code>语句了:原来<code class="literal">printf</code>也是一个函数,上例中的<code class="literal">printf("sin(pi/2)=%f\nln1=%f\n", sin(pi/2), log(1.0))</code>是带三个参数的函数调用,而函数调用也是一种表达式,因此<code class="literal">printf</code>语句也是表达式语句的一种。但是<code class="literal">printf</code>感觉不像一个数学函数,为什么呢?因为像<code class="literal">log</code>这种函数,我们传进去一个参数会得到一个返回值,我们调用<code class="literal">log</code>函数就是为了得到它的返回值,至于<code class="literal">printf</code>,我们并不关心它的返回值(事实上它也有返回值,表示实际打印的字符数),我们调用<code class="literal">printf</code>不是为了得到它的返回值,而是为了利用它所产生的副作用(Side Effect)<a id="id2712601" class="indexterm"></a>--打印。<span class="emphasis"><em>C语言的函数可以有Side Effect,这一点是它和数学函数在概念上的根本区别</em></span>。</p><p>Side Effect这个概念也适用于运算符组成的表达式。比如<code class="literal">a + b</code>这个表达式也可以看成一个函数调用,把运算符<code class="literal">+</code>看作函数,它的两个参数是<code class="literal">a</code>和<code class="literal">b</code>,返回值是两个参数的和,传入两个参数,得到一个返回值,并没有产生任何Side Effect。而赋值运算符是有Side Effect的,如果把<code class="literal">a = b</code>这个表达式看成函数调用,返回值就是所赋的值,既是<code class="literal">b</code>的值也是<code class="literal">a</code>的值,但除此之外还产生了Side Effect,就是变量<code class="literal">a</code>被改变了,改变计算机存储单元里的数据或者做输入输出操作都算Side Effect。</p><p>回想一下我们的学习过程,一开始我们说赋值是一种语句,后来学了表达式,我们说赋值语句是表达式语句的一种;一开始我们说<code class="literal">printf</code>是一种语句,现在学了函数,我们又说<code class="literal">printf</code>也是表达式语句的一种。随着我们一步步的学习,把原来看似不同类型的语句统一成一种语句了。学习的过程总是这样,初学者一开始接触的很多概念从严格意义上说是错的,但是很容易理解,随着一步步学习,在理解原有概念的基础上不断纠正,不断泛化(Generalize)<a id="id2712698" class="indexterm"></a>。比如一年级老师说小数不能减大数,其实这个概念是错的,后来引入了负数就可以减了,后来引入了分数,原来的正数和负数的概念就泛化为整数,上初中学了无理数,原来的整数和分数的概念就泛化为有理数,再上高中学了复数,有理数和无理数的概念就泛化为实数。坦白说,到目前为止本书的很多说法都是不完全正确的,但这是学习理解的必经阶段,到后面的章节都会逐步纠正的。</p><p>程序第一行的#号(Pound Sign,Number Sign或Hash Sign)<a id="id2712726" class="indexterm"></a>和<code class="literal">include</code>表示包含一个头文件(Header File)<a id="id2712740" class="indexterm"></a>,后面尖括号(Angel Bracket)<a id="id2712748" class="indexterm"></a>中就是文件名(这些头文件通常位于<code class="literal">/usr/include</code>目录下)。头文件中声明了我们程序中使用的库函数,根据先声明后使用的原则,要使用<code class="literal">printf</code>函数必须包含<code class="literal">stdio.h</code>,要使用数学函数必须包含<code class="literal">math.h</code>,如果什么库函数都不使用就不必包含任何头文件,例如写一个程序<code class="literal">int main(void){int a;a=2;return 0;}</code>,不需要包含头文件就可以编译通过,当然这个程序什么也做不了。</p><p>使用<code class="literal">math.h</code>中声明的库函数还有一点特殊之处,<code class="literal">gcc</code>命令行必须加<code class="literal">-lm</code>选项,因为数学函数位于<code class="literal">libm.so</code>库文件中(这些库文件通常位于<code class="literal">/lib</code>目录下),<code class="literal">-lm</code>选项告诉编译器,我们程序中用到的数学函数要到这个库文件里找。本书用到的大部分库函数(例如<code class="literal">printf</code>)位于<code class="literal">libc.so</code>库文件中,使用<code class="literal">libc.so</code>中的库函数在编译时不需要加<code class="literal">-lc</code>选项,当然加了也不算错,因为这个选项是<code class="literal">gcc</code>的默认选项。关于头文件和库函数目前理解这么多就可以了,到<a class="xref" href="ch20.html#link">第 20 章 <i>链接详解</i></a>再详细解释。</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">C标准库和glibc</h3><p>C标准主要由两部分组成,一部分描述C的语法,另一部分描述C标准库。C标准库定义了一组标准头文件,每个头文件中包含一些相关的函数、变量、类型声明和宏定义。要在一个平台上支持C语言,不仅要实现C编译器,还要实现C标准库,这样的实现才算符合C标准。不符合C标准的实现也是存在的,例如很多单片机的C语言开发工具中只有C编译器而没有完整的C标准库。</p><p>在Linux平台上最广泛使用的C函数库是<code class="literal">glibc</code>,其中包括C标准库的实现,也包括本书第三部分介绍的所有系统函数。几乎所有C程序都要调用<code class="literal">glibc</code>的库函数,所以<code class="literal">glibc</code>是Linux平台C程序运行的基础。<code class="literal">glibc</code>提供一组头文件和一组库文件,最基本、最常用的C标准库函数和系统函数在<code class="literal">libc.so</code>库文件中,几乎所有C程序的运行都依赖于<code class="literal">libc.so</code>,有些做数学计算的C程序依赖于<code class="literal">libm.so</code>,以后我们还会看到多线程的C程序依赖于<code class="literal">libpthread.so</code>。以后我说<code class="literal">libc</code>时专指<code class="literal">libc.so</code>这个库文件,而说<code class="literal">glibc</code>时指的是<code class="literal">glibc</code>提供的所有库文件。</p><p><code class="literal">glibc</code>并不是Linux平台唯一的基础C函数库,也有人在开发别的C函数库,比如适用于嵌入式系统的<code class="literal">uClibc</code>。</p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="ch03.html">上一级</a></td><td width="40%" align="right"> <a accesskey="n" href="ch03s02.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">第 3 章 简单函数 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 2. 自定义函数</td></tr></table></div></body></html>