Relearning MSX #42: Functions in MSX-C (Part 3)
Posted by Javi Lavandeira in How-to, MSX, Retro, Technology | April 12, 2016The previous post dealt with function arguments and private variables inside functions. Today we’re going to complete our study of functions by looking at how we can return values from them.
Let’s jump into it.
Functions that return a value
We saw earlier that there are functions such as putchar() that take an argument and perform some kind of action with it, and there are functions such as getch() that first perform some action and then return a value. We’ve already seen how to write functions of the first type, and now we’re going to see how to define the others.
Defining a function that returns a value
The image below illustrates how to define a function that returns a value. Notice that before the function name we declare the type of the value it returns, and that at some point the function contains a return statement (or sometimes more than one):
The short program below shows how to define and use a function that returns a value. For example, the add() function takes two arguments and returns their sum:
We can use a function that returns a value of type int in any situation where we can use a normal int. For example, we can assign it to a variable:
i = add(1, 2); /* assigns the result of (1+2) to variable i */
We can even use a function call as an argument for another function:
i = add(1, add(2, 3)); /* assigns the result of (1 + (2+3)) to variable i */
The same applies for all other types: a function that returns a char can be used in any place where a char value is allowed, and so on.
The return value
A function always returns a value of the type in its definition. This means that we don’t need to manually cast any variables into the correct type (as we saw when we discussed data types). MSX-C will automatically convert the return value into the appropriate type for us.
As an example, consider the following function definition:
The next() function takes a character code in argument c and an integer value in argument n. We can use this function to obtain the character n positions after c. As we saw in the post about data types, the sum of a char and an int always results in an int. In this case we have defined next() to return a char, so MSX-C automatically does the conversion of (c + n) to a char before returning it.
Since we can use a function that returns a char anywhere where a char is expected, we can use this next() function as an argument for functions such as putchar():
putchar(next('A', 1)); /* Print character B on the screen */
Regardless of the type, a function in C can only return a single value. However, there’s a way to work around this limitation. We’ll see this soon, when we learn about pointers.
The VOID type
MSX-C was released before the C programming language was standardized into the ANSI C standard. Back then a function that didn’t explicitly declare a return type defaulted to int. To illustrate this, the two function definitions below are exactly the same in K&R C (which is the version of C implemented by MSX-C):
In modern C these two functions would both produce compiler warnings, but MSX-C doesn’t care: if we define a variable to return a value but then it doesn’t, we’ll be fine as long as we don’t try and do anything with the returned value. This means that we can call the function all we want, but without assigning it to a variable or passing it as an argument to other functions.
By the time MSX-C became available there were already dialects of C that supported the void type for functions that didn’t return a value, and because of this the VOID type was introduced in MSX-C. It’s written in uppercase because it’s not an actual type supported by the compiler, but a redefinition of the char type.
From this point we’ll define all functions that don’t return a value as VOID. This doesn’t affect the functionality at all, but it removes ambiguity and makes the program easier to follow. For example, we’d write the function above like this:
Summary
In this post we’ve learnt how to write functions that return values. We’ve seen how the compiler automatically converts the value returned by the function to the appropriate type, and we’ve learnt about the VOID type for functions that don’t return anything.
With this we’ve already seen functions in C and can move to the next subject.
In the next post
In the next post we’ll learn about storage classes: how variables behave inside a function depending on how the variable was defined, and also variable scope.
This series of articles is supported by your donations. If you’re willing and able to donate, please visit the link below to register a small pledge. Every little amount helps.
Javi Lavandeira’s Patreon page