⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter 10 functions -- valvano.htm

📁 介绍了在嵌入式系统中如何用c来设计嵌入式软件
💻 HTM
📖 第 1 页 / 共 4 页
字号:
them. In C, parentheses following a name are associated with the name before the 
preceding asterisk is applied to the result. Therefore,</FONT></P>
<DIR>
<P><CODE>int *fp(int);</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">would be taken as</FONT></P>
<DIR>
<P><CODE>int *(fp(int));</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">saying that <B>fp</B> is a function 
returning a pointer to an integer, which is not at all like the declaration in 
Listing 10-1.</FONT></P>
<P>&nbsp;</P>
<P><B><I><FONT face=Helvetica,Arial><A name=DEFINITIONS></A>Function 
Definitions</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">The second way to declare a function is to 
fully describe it; that is, to <I>define</I> it. Obviously every function must 
be defined somewhere. So if we organize our source code in a bottom up fashion, 
we would place the lowest level functions first, followed by the function that 
calls these low level functions. It is possible to define large project in C 
without ever using a standard declaration (function prototype). On the other 
hand, most programmers like the top-down approach illustrated in the following 
example. This example includes three modules: the LCD interface, the COP 
functions, and some Timer routines. Notice the function names are chosen to 
reflect the module in which they are defined. If you are a C++ programmer, 
consider the similarities between this C function call <B>LCDclear()</B> and a 
C++ LCD class and a call to a member function <B>LCD.clear()</B>. The *.H files 
contain function declarations and the *.C files contain the 
implementations.</FONT></P>
<DIR>
<P><CODE>#include "HC12.H"<BR>#include "LCD12.H"<BR>#include 
"COP12.H"<BR>#include "Timer.H"<BR>void main(void){ char letter; int n=0; 
<BR>&nbsp;&nbsp;&nbsp;COPinit(); // Enable TOF interrupt to make COP 
happy<BR>&nbsp;&nbsp;&nbsp;LCDinit();<BR>&nbsp;&nbsp;&nbsp;TimerInit()<BR>&nbsp;&nbsp;&nbsp;LCDString("Adapt812 
LCD");<BR>&nbsp;&nbsp;&nbsp;TimerMsWait(1000);<BR>&nbsp;&nbsp;&nbsp;LCDclear();<BR>&nbsp;&nbsp;&nbsp;letter='a'-1;<BR>&nbsp;&nbsp;&nbsp;while(1){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if 
(letter=='z')<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;letter='a';<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;letter++;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCDputchar(letter);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimerMsWait(250);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(++n==16){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n=0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCDclear();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;}<BR>}<BR>#include 
"LCD12.C"<BR>#include "COP12.C"<BR>#include "Timer.C"<BR>#include 
"VECTORS.C"</CODE></P></DIR>
<ADDRESS>Listing 10-2: Modular approach to software development</ADDRESS>
<ADDRESS>&nbsp;</ADDRESS>
<P><FONT face="Times New Roman,Times">C function definitions have the following 
form</FONT></P>
<DIR>
<P><I><FONT face="Times New Roman,Times">type Name</FONT></I><FONT 
face="Times New Roman,Times">(<I>parameter 
list</I>){<BR><I>CompoundStatement</I><BR><I>};</I></FONT></P></DIR>
<P><FONT face="Times New Roman,Times">Just like the function declaration, we 
begin the definition with its <B>type</B>. The <B>type</B> specifies the 
function return parameter. If there is no return parameter we can use 
<B>void</B> or leave it blank. <B>Name</B> is the name of the function. The 
<B>parameter list </B>is a list of zero or more names for the arguments that 
will be received by the function when it is called. Both the type and name of 
each input parameter is required. As we will see later, ICC11 and ICC12 pass the 
first (left most) parameter in Reg D, and the remaining parameters are passed on 
the stack. Then once inside the function, ICC12 and ICC12 functions will push 
register D on the stack, so after that all parameters are on the stack. The 
output parameter is returned in register D. 8-bit output parameters are promoted 
to 16-bits. Similarly, most input parameters are also passed as 16-bit values, 
8-bit characters are promoted to 16-bit integers and arrays and strings are 
passed as pointers. The exception to this rule is 32-bit longs and 32-bit 
floats.</FONT></P>
<P><FONT face="Times New Roman,Times">Although a character is passed as a word, 
we are free to declare its formal argument as either character or word. If it is 
declared as a character, only the low-order byte of the actual argument will be 
referenced. If it is declared as an integer, then all 16 bits will be 
referenced. </FONT></P>
<P><FONT face="Times New Roman,Times">It is generally more efficient to 
reference integers than characters because there is no need for a machine 
instruction to set the high-order byte. So it is common to see situations in 
which a character is passed to a function which declares the argument to be an 
integer. But there is one caveat here: not all C compilers promote character 
arguments to integers when passing them to functions; the result is an 
unpredictable value in the high-order byte of the argument. This should be 
remembered as a portability issue.</FONT></P>
<P><FONT face="Times New Roman,Times">Since there is no way in C to declare 
strings, we cannot declare formal arguments as strings, but we can declare them 
as character pointers or arrays. In fact, as we have seen, C does not recognize 
strings, but arrays of characters. The string notation is merely a shorthand way 
of writing a constant array of characters.</FONT></P>
<P><FONT face="Times New Roman,Times">Furthermore, since an unsubscripted array 
name yields the array's address and since arguments are passed by value, an 
array argument is effectively a pointer to the array. It follows that, the 
formal argument declarations <B>arg[]</B> and <B>*arg</B> are really equivalent. 
The compiler takes both as pointer declarations. Array dimensions in argument 
declarations are ignored by the compiler since the function has no control over 
the size of arrays whose addresses are passed to it. It must either assume an 
array's size, receive its size as another argument, or obtain it 
elsewhere.</FONT></P>
<P><FONT face="Times New Roman,Times">The last, and most important, part of the 
function definition above is <B>CompoundStatement</B>. This is where the action 
occurs. Since compound statements may contain local declarations, simple 
statements, and other compound statements, it follows that functions may 
implement algorithms of any complexity and may be written in a structured style. 
Nesting of compound statements is permitted without limit.</FONT></P>
<P><FONT face="Times New Roman,Times">As an example of a function definition 
consider</FONT></P>
<DIR>
<P><CODE>int add3(int z1, int z2, int z3){ int 
y;<BR>&nbsp;&nbsp;&nbsp;&nbsp;y=z1+z2+z3;<BR>&nbsp;&nbsp;&nbsp;&nbsp;return(y);}</CODE></P></DIR>
<ADDRESS>Listing 10-3: Example function with 3 inputs and one output.</ADDRESS>
<ADDRESS>&nbsp;</ADDRESS>
<P><FONT face="Times New Roman,Times">Here is a function named <B>add3</B> which 
takes three input arguments.</FONT></P>
<P>&nbsp;</P>
<P><B><I><FONT face=Helvetica,Arial><A name=CALLS></A>Function 
Calls</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">A function is called by writing its name 
followed by a parenthesized list of argument expressions. The general form 
is</FONT></P>
<P><I><FONT face="Times New Roman,Times">Name</FONT></I><FONT 
face="Times New Roman,Times"> <B>(</B><I>parameter list</I><B>)</B></FONT></P>
<P><FONT face="Times New Roman,Times">where <B>Name</B> is the name of the 
function to be called. The<B><I> </I>parameter list<I> </I></B>specifies the 
particular input parameters used in this call. Notice that each input parameter 
is in fact an expression. It may be as simple as a variable name or a constant, 
or it may be arbitrarily complex, including perhaps other function calls. 
Whatever the case, the resulting value is pushed onto the stack where it is 
passed to the called function.</FONT></P>
<P><FONT face="Times New Roman,Times">C programs evaluate arguments from left to 
right, pushing them onto the stack in that order. As we will see later, the 
ICC11 and ICC12 compilers allocate the stack space for the parameters at the 
start of the program that will make the function call. Then the values are 
stored into the pre-allocated stack position before it calls the function. On 
return, the return parameter is located in Reg D. The input parameters are 
removed from the stack at the end of the program.</FONT></P>
<P><FONT face="Times New Roman,Times">When the called function receives control, 
it refers to the first actual argument using the name of the first formal 
argument. The second formal argument refers to the second actual argument, and 
so on. In other words, actual and formal arguments are matched by position in 
their respective lists. Extreme care must be taken to ensure that these lists 
have the same number and type of arguments. </FONT></P>
<P><FONT face="Times New Roman,Times">It was mentioned earlier, that function 
calls appear in expressions. But, since expressions are legal statements, and 
since expressions may consist of only a function call, it follows that a 
function call may be written as a complete statement. Thus the 
statement</FONT></P>
<DIR>
<P><CODE>add3(--counter,time+5,3);</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">is legal. It calls <B>add3()</B>, passing 
it three arguments --<B>counter</B>, <B>time+5</B>, and <B>3</B>. Since this 
call is not part of a larger expression, the value that <B>add3()</B> returns 
will be ignored. As a better example, consider</FONT></P>
<DIR>
<P><CODE>y=add3(--counter,time+5,3);</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">which is also an expression. It calls 
<B>add3()</B> with the same arguments as before but this time it assigns the 
returned value to <B>y</B>. It is a mistake to use an assignment statement like 
the above with a function that does not return an output parameter.</FONT></P>
<P><FONT face="Times New Roman,Times">The ability to pass one function a pointer 
to another function is a very powerful feature of the C language. It enables a 
function to call any of several other functions with the caller determining 
which subordinate function is to be called. </FONT></P>
<DIR>
<P><CODE>int fun1(int 
input){<BR>&nbsp;&nbsp;&nbsp;return(input+1);&nbsp;&nbsp;&nbsp;&nbsp;// this 
adds 1<BR>};<BR>int fun2(int 
input){<BR>&nbsp;&nbsp;&nbsp;return(input+2);&nbsp;&nbsp;&nbsp;&nbsp;// this 
adds 2<BR>};<BR>int execute(int (*fp)(int)){ int 
data;<BR>&nbsp;&nbsp;&nbsp;data=(*fp)(5);&nbsp;// 
data=fun1(5);<BR>&nbsp;&nbsp;&nbsp;return (data);<BR>};<BR>void main(void){ int 
result;<BR>&nbsp;&nbsp;&nbsp;result=execute(&amp;fun1);&nbsp;// 
result=fun1(5);<BR>&nbsp;&nbsp;&nbsp;result=execute(&amp;fun2);&nbsp;// 
result=fun2(5);<BR>};</CODE></P></DIR>
<ADDRESS>Listing 10-4: Example of passing a function pointer</ADDRESS>
<P><FONT face="Times New Roman,Times">Notice that <B>fp</B> is declared to be a 
function pointer. Also, notice that the designated function is called by writing 
an expression of the same form as the declaration. </FONT></P>
<P><B><I><FONT face=Helvetica,Arial><A name=ARGUMENTS></A>Argument 
Passing</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">Now let us take a closer look at the 
matter of argument passing. With respect to the method by which arguments are 
passed, two types of subroutine calls are used in programming languages--<I>call 
by reference</I> and <I>call by value</I>.</FONT></P>
<P><FONT face="Times New Roman,Times">The<I> call by reference</I> method passes 
arguments in such a way that references to the formal arguments become, in 
effect, references to the actual arguments. In other words, references 
(pointers) to the actual arguments are passed, instead of copies of the actual 
arguments themselves. In this scheme, assignment statements have implied side 
effects on the actual arguments; that is, variables passed to a function are 
affected by changes to the formal arguments. Sometimes side effects are 
beneficial, and some times they are not. Since C supports only one formal output 
parameter, we can implement additional output parameters using call by 
reference. In this way the function can return parameters back using the 
reference. As an example recall the fifo queue program shown earlier in<A 
href="http://www.ece.utexas.edu/~valvano/embed/chap8/chap8.htm#FIFOQ"> Listing 
8-7</A>. The function <B>GetFifo</B>, shown below, returns two parameters. The 
regular formal parameter is a boolean specifying whether or not the request was 
successful, and the actual data removed from the queue is returned via the call 
by reference. The calling program <B>InChar</B> passes the address of its local 
variable data. The assignment statement <B>*datapt=Fifo[GetI++];</B> within 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -