虽然部分C语言函数的返回值与其参数存在对应关系,但是它与数学里的函数不是同一概念。有的书上把它定义为完成特定任务的代码集合。
C语言函数的格式为:返回值数据格式 函数名(参数列表){函数体}, 函数可以没有返回值,参数列表也可以为空。函数返回值可以是除数组外的任意类型,参数数据类型为C的所有数据类型。函数的定义一般有两个步骤,先是函数声明,然后是实现。一般在头文件中声明函数,然后在源文件中写实现代码。下面列举几个声明与实现的实例:
//************** stcio.h
#ifndef __STCIO_H_
#define __STCIO_H_
//#define STC8F
//#define STC15
#ifdef STC15
#include "stc15w4k.h"
#endif
#ifdef STC8F
#include "stc8f.h"
#endif
#include "mytype.h"
typedef enum
{
BI_IO = 0, //bidirectional I/O
PP_OUT, //push_pull out
HI_IN, //high impendence in
ODR_IO //open drain I/O
}STCIOTYPE;
//*******************************************************************
typedef enum
{
GPIO_P0 = 0x01,
GPIO_P1 = 0x02,
GPIO_P2 = 0x04,
GPIO_P3 = 0x08,
GPIO_P4 = 0x10,
GPIO_P5 = 0x20,
GPIO_P6 = 0x40,
GPIO_P7 = 0x80,
}STC_PORT;
//********************************************************************
typedef enum
{
GPIO_PIN0 = 0x01,
GPIO_PIN1 = 0x02,
GPIO_PIN2 = 0x04,
GPIO_PIN3 = 0x08,
GPIO_PIN4 = 0x10,
GPIO_PIN5 = 0x20,
GPIO_PIN6 = 0x40,
GPIO_PIN7 = 0x80,
}IO_PIN;
**********************************************************************/
void STC_PortPinsInit(STC_PORT mPort, ui8 mPins, STCIOTYPE iotype); //init I/O pin type
/*
Example:
STC_IOPinInit(GPIO_P7, GPIO_PIN7,BI_IO);
*/
**********************************************************************/
void STC_IOInit(ui8 mPorts, ui8 mPins, STCIOTYPE iotype); //init ports' bit I/O type
/*
Example:
STC_IOInit(0xFF, 0xFF,BI_IO);
*/
#endif
//
//**********stcio.c
#include "stcio.h"
**********************************************************************/
void STC_PortPinsInit(STC_PORT mPort, ui8 mPins, STCIOTYPE iotype) //init I/O pin type
{
switch(mPort)
{
case GPIO_P0:
switch(iotype)
{
case BI_IO:
P0M0 &= ~mPins;
P0M1 &= ~mPins;
break;
case PP_OUT:
P0M0 |= mPins;
P0M1 &= ~mPins;
break;
case HI_IN:
P0M0 &= ~mPins;
P0M1 |= mPins;
break;
case ODR_IO:
P0M0 |= mPins;
P0M1 |= mPins;
break;
}
break;
case GPIO_P1:
switch(iotype)
{
case BI_IO:
P1M0 &= ~mPins;
P1M1 &= ~mPins;
break;
case PP_OUT:
P1M0 |= mPins;
P1M1 &= ~mPins;
break;
case HI_IN:
P1M0 &= ~mPins;
P1M1 |= mPins;
break;
case ODR_IO:
P1M0 |= mPins;
P1M1 |= mPins;
break;
}
break;
case GPIO_P2:
switch(iotype)
{
case BI_IO:
P2M0 &= ~mPins;
P2M1 &= ~mPins;
break;
case PP_OUT:
P2M0 |= mPins;
P2M1 &= ~mPins;
break;
case HI_IN:
P2M0 &= ~mPins;
P2M1 |= mPins;
break;
case ODR_IO:
P2M0 |= mPins;
P2M1 |= mPins;
break;
}
break;
case GPIO_P3:
switch(iotype)
{
case BI_IO:
P3M0 &= ~mPins;
P3M1 &= ~mPins;
break;
case PP_OUT:
P3M0 |= mPins;
P3M1 &= ~mPins;
break;
case HI_IN:
P3M0 &= ~mPins;
P3M1 |= mPins;
break;
case ODR_IO:
P3M0 |= mPins;
P3M1 |= mPins;
break;
}
break;
case GPIO_P4:
switch(iotype)
{
case BI_IO:
P4M0 &= ~mPins;
P4M1 &= ~mPins;
break;
case PP_OUT:
P4M0 |= mPins;
P4M1 &= ~mPins;
break;
case HI_IN:
P4M0 &= ~mPins;
P4M1 |= mPins;
break;
case ODR_IO:
P4M0 |= mPins;
P4M1 |= mPins;
break;
}
break;
case GPIO_P5:
switch(iotype)
{
case BI_IO:
P5M0 &= ~mPins;
P5M1 &= ~mPins;
break;
case PP_OUT:
P5M0 |= mPins;
P5M1 &= ~mPins;
break;
case HI_IN:
P5M0 &= ~mPins;
P5M1 |= mPins;
break;
case ODR_IO:
P5M0 |= mPins;
P5M1 |= mPins;
break;
}
break;
case GPIO_P6:
switch(iotype)
{
case BI_IO:
P6M0 &= ~mPins;
P6M1 &= ~mPins;
break;
case PP_OUT:
P6M0 |= mPins;
P6M1 &= ~mPins;
break;
case HI_IN:
P6M0 &= ~mPins;
P6M1 |= mPins;
break;
case ODR_IO:
P6M0 |= mPins;
P6M1 |= mPins;
break;
}
break;
case GPIO_P7:
switch(iotype)
{
case BI_IO:
P7M0 &= ~mPins;
P7M1 &= ~mPins;
break;
case PP_OUT:
P7M0 |= mPins;
P7M1 &= ~mPins;
break;
case HI_IN:
P7M0 &= ~mPins;
P7M1 |= mPins;
break;
case ODR_IO:
P7M0 |= mPins;
P7M1 |= mPins;
break;
}
break;
}
}
**********************************************************************/
void STC_IOInit(ui8 mPorts, ui8 mPins, STCIOTYPE iotype) //init ports' bit I/O type
{
ui8 i,j;
for(i = 0; i < 8; i++)
{
j = mPorts&(1 << i);
if(j)
{
STC_PortPinsInit(j, mPins, iotype);
}
}
}
//End of STC_IOInit(ui8 mPorts, ui8 mPins, STCIOTYPE iotype)
上面函数的返回值皆为空,但其参数列表不为空,下面有一个返回值为空(void),参数列表也为空的例子:
ltc1658is8.h//LTC1658IS8 driver
#ifndef __LTC1658IS8_H__
#define __LTC1658IS8_H__
#include "myport.h" //defined ltc1658DIN,ltc1658CS,ltc1658CLK
#include "mytype.h"
#include "delay.h"
//***********************************************************
void LTC1658_CLK();
//************************************************************
void LTC1658_DacOutput(ui16 mData);
#endif
//ltc1658is8.c//LTC1658IS8 driver
#include "ltc1658is8.h"
//***********************************************************
void LTC1658_CLK()
{
ltc1658CLK = 1;
Delayxus(1,8);
ltc1658CLK = 0;
Delayxus(1,8);
}
//************************************************************
void LTC1658_DacOutput(ui16 mData)
{
ui8 i;
ltc1658CS = 0;
ltc1658CLK = 0;
Delayxus(1,8);
for(i = 0; i < 16; i++)
{
mData = (mData << 1);
if(CY)
ltc1658DIN = 1;
else
ltc1658DIN = 0;
Delayxus(1,8);
LTC1658_CLK();
}
ltc1658CS = 1;
ltc1658CLK = 1;
}
在定义有返回值函数时,须注意那些可以做返回值哪些不能,先不下结论。有书上说,数组不可以做返回值, 整个数组肯定不可以做返回值,返回值不可能为多个,那数组名呢?数组名实际是一个指针,指向数组的首地址。请看下面例子:
编译结果如下:
编译成功,说明数组名是可以做返回值的,因为它实际是个指针。同样数组元素(数组名加下标,如destArray[0]) ,标准C数据及标准C的扩展数据都看做函数参数(类型),除数组外都可做返回值(类型)。
Keil C51的扩展数据类型可否做函数返回值与参数呢?sbit,srf,srf16 类型是既不能做返回值,也不可做参数的。