• Nem Talált Eredményt

Defining, calling and declaring functions

In document Mechatronic Systems Programming in C++ (Pldal 109-112)

II. fejezet - Modular programming in C++

1. The basics of functions

1.1. Defining, calling and declaring functions

C++ Standard Library provides us many useful predefined functions. We only have to declare these functions before using them. For that purpose, the corresponding header file should be included in the source code. The following table enumerates some frequently used functions and the corresponding include files:

function header file

sqrt() cmath

isalpha() cctype

function header file

atoi() cstdlib

rand() cstdlib

strlen() cstring

wcslen() cwchar

Contrary to Library functions, our own functions should always be defined as well. This function definition can be placed anywhere in a C++ program, but only once. If the definition of a function precedes the place where it is called (used), then it is also a declaration.

The general form of a function definition is the following (the signs 〈 〉 indicate optional parts): A parameter declaration list in the function header enumerates each parameter separated by each other by a comma, and every parameter is preceded by its type.

II.1. ábra - Function definition

A storage class can also be given before the return type in the definition of functions. In the case of functions, the default storage class is extern, which indicates that the function can be accessed from other modules. If the accessibility of a function needs to be restricted to a given module, the static storage class should be used.

(When parameters are declared, only the register storage class can be specified). If a function is intended to be placed within our own namespace, then the definition and the prototype of that function have to be put in the chosen namespace block. (Storage classes and namespaces are detailed later in this book.)

The next example contains a function that calculates the sum of the first n positive integer numbers. The function isum() expects an int type value and returns an int type result.

int isum(int n) {

int s = 0;

for (int i=1; i<=n; i++) s += i;

return s;

}

Suppose that in the source code, the definition of isum() is before the main () function from where the function isum() is called:

int main() {

cout << isum(10) << endl;

int s = isum(7) * isum(10) + 2;

}

When a function is called , the name of the function is followed by a list of arguments separated from each other by a comma. The steps of calling a function can be traced on II.2. ábra - Steps of calling a function.

function_name (〈 argument1, argument2, … argumentn〉 )

Parentheses should be used even if a function does not have any parameters. A function can be called from anywhere where a statement can be given.

The order in which arguments are evaluated is not defined by the language C++. Function call operators guarantee only one thing: by the time control is passed to a called function, the argument list has completely been evaluated (together with all of its side-effects).

II.2. ábra - Steps of calling a function

C++ standards require that functions have to be declared before they are called. Defining a function is therefore declaring a function. Then it may be logical to ask how we can make sure that the called function would always precede the place where it is called. Of course, this cannot be ensured because there are functions calling each other. In case the functions main () and isum() are swapped in the previous example, we get compilation errors until the prototype containing the whole description of the function is placed before the function is called:

int isum(int); // prototype

int main() {

cout << isum(10) << endl;

int s = isum(7) * isum(10) + 2;

}

int isum(int n) {

int s = 0;

for (int i=1; i<=n; i++) s += i;

return s;

}

The complete declaration of a function (its prototype ) contains the name and the type of the function and provides information about the number and the type of the parameters:

return_value function_name(〈 parameter declaration list〉 );

return_value function_name(〈 type_list〉 );

C++ compilers compile function calls if the prototype is already known:

• checks the compatibility of the number and the types of parameters by comparing these parameters with the argument list,

• converts arguments according to the types defined in the prototype and not according to the rules of automatic conversion.

(It should be noted that function definitions replace prototypes.) In most cases, a function header is used as a prototype, and it ends with a semicolon. In prototypes, parameter names do not have any importance, they can be left out or any other name can be used. The following prototypes are completely equal for compilers:

int isum(int);

int isum(int n);

int isum(int lots);

The prototype of a function can figure many times in the source code; however, they have to be the same, only parameter names can be different.

It should be noted that the prototype of functions without parameters is interpreted differently by C and C++

languages:

declaration C interpretation C++ interpretation

type funct(); type funct(...); type funct(void);

type funct(...); type funct(...); type funct(...);

type funct(void); type funct(void); type funct(void);

C++ makes it possible that a parameter list containing at least one parameter should end with three dots (...). A function defined in that way can be called with at least one parameter but also with any number or type of arguments. Let's look at the prototype of the function sscanf ().

int sscanf ( const char * str, const char * format, ...);

Chapter (5. szakasz - Exception handling) dealing with exceptions also mentioned that the transferring (throw) of exceptions to the caller function can be enabled or disabled in function header. When the keyword throw is used, the definition of functions is modified in the following way:

return_type function_name (〈 parameterlist〉 ) 〈 throw(〈 type_list〉 )〉

{

local definitions and declarations〉

statements〉

return 〈 expression〉 ; }

The prototype corresponding to the definition also has to contain the keyword throw:

return_type function _ name (〈 parameterlist〉 ) 〈 throw(〈 type_list〉 )〉 ; Let's see some prototypes mentioning the type of the thrown exceptions:

int funct() throw(int, const char*); // int and const char*

int funct(); // all

int funct() throw(); // not any

In document Mechatronic Systems Programming in C++ (Pldal 109-112)