Welsh Centre for Printing and Coatings
Tuesday October 22, 2024
C is a high-level structured programming language which is often used for writing microcontroller applications. This weeks lecture will cover good coding practices, C language operators and how they can be grouped as well as flow control structures.
In this chapter we will be looking at how to produce clear well commented programs; data transfer, arithmetic, logic and relational operators; and flow control structures including if
, switch-case
, for
and while
.
Code Formatting, comments, pre-processor directives, statements and operators
/*
* This is a demonstration program for EG-151 microcontrollers that shows a tidy well commented program.
* This program asks a user to input two numbers and uses the function findmax to determine which is the largest.
*
* Author: Ben Clifford
* Date: 12/10/2019
*/
// include library files
#include <stdio.h> //Required for scanf and printf
// main function
int main(void) {
// Variable Declarations
int num1, num2, maxnum;
// Function Declarations
int findmax(int, int);
printf("Enter the first number: ");
scanf("%u", &num1);
printf("Enter the second number: ");
scanf("%u", &num2);
/* invoke the function findmax passing numl and num2
* as arguments and storing the result in the variable maxnum
*/
maxnum = findmax(num1, num2);
printf("The maximum number is %u", maxnum);
}
// findmax Function Definition
int findmax(int x, int y) {
int maximum_number;
if (x >= y) {
maximum_number = x;
}
else {
maximum_number = y;
}
return maximum_number;
}
/* comment */
and can span multiple lines//
if they are on a single line.Single line comment \(\rightarrow\) typically found after a statement
Multi line comment \(\rightarrow\) typically used at the start of a program or to detail a block of code or a function
#
and evaluates them before compilation.__
” characters.#include
and #define
.#include
directiveThe #include
directive is used to include header files which contain declarations of existing and frequently used functions that can be substituted into your program.
#define
directiveThe #define
directive is used to define a macro – when the macro name appears in code it will be replaced with the definition stated.
;
.Figure 1 is a schematic diagram of the C function. You can think of it as something that takes some inputs (arguments) and returns some output.
A simple function is presented below.
The term variable is used for a name which describes a memory address. These names follow the same naming convention as used for functions1.
For example, a variable named num1
describes a particular memory address at which the first number is found and a second variable num2
describes a second memory address while a third variable, total
, is a third memory address.
In a function we may then have the following statements:
Each statement or instruction is made up of operators and operands, where the operator represents an action and the operands represents the data.
In C, the operators can be split into four categories based on the type of actions that they perform3.
They are:
We will consider each of these in the following sections.
In the C language, the data transfer operations are mostly covered by assignment without ever having to deal directly with the registers.
The order of arithmetic operations follow the BODMAS (BIDMAS) rules4.
Operator | Used for |
---|---|
+ |
Addition |
- |
Subtraction |
* |
Multiplication |
/ |
Division |
% |
Modulus |
++ |
Increment |
-- |
Decrement |
Assume a
, b
, c
and r = 2
are defined as variable of type integer (int
)5.
Brackets can be used to improve readability6
Assume d
to h
are defined as integer variables (int
) and i
as a floating point number (float
):
d = 5 / 3; // -> d = 1: gives the whole part of the fraction
e = 5 % 3; // -> e = 2: gives thremainder of the fraction
f = 6 % 3; // -> f = 0: gives 0 as there is no remainder
g = 5.5 / 2; // -> g = 2: float is converted to int
h = 5.5 % 2; // -> invalid – will not compile
i = 5.5 / 2; // -> i = 1.75 - evaluates correctly if i is defined as a float
Logical operators are used in expressions which return true (1
) or false (0
).
Operator | Meaning |
---|---|
&& |
Logical and |
|| |
Logical or |
! . |
Logical not |
&&
)||
)!
)In addition to the logical operators designed to evaluate multiple conditions there are bitwise logical operators which operate on the binary digits (bits) of their operands.
Operator | Used for |
---|---|
& |
bitwise AND |
| |
bitwise OR |
^ |
bitwise XOR |
~ |
bitwise NOT |
>> |
shift right |
<< |
shift left |
\[ \begin{array}{lrr} & 1010 & 0011 \\ \& & 1101 & 0101 \\\hline & 1000 & 0001 \end{array} \]
\[ \begin{array}{lrr} & 1010 & 0011 \\ | & 1101 & 0101 \\\hline & 1111 & 0111 \end{array} \]
\[ \begin{array}{lrr} \sim & 1010 & 0011 \\\hline & 0101 & 1100 \end{array} \]
PTAPE = 0x0F; // bit pattern: 0000 1111
PTAD = 0xF0; // bit pattern: 1111 0000
PTAD = PTAD | 0x0C; // bit pattern: 1111 1100
Since XORing any bit with a 1 forces it to return the opposite value, it can be used to toggle the state of a port:
The final group of operators are the relational operators which are used to test a relationship between two variables or a variable and data.
Relational operator | Meaning |
---|---|
== |
is equal to |
!= |
is not equal to |
< |
is less than |
<= |
is less than or equal to |
> |
is greater than |
>= |
is greater than or equal to |
These are discussed in Section 2.
Flow control statements if
, for
, while
, and switch
Figure 2 illustrates the flow control structures that are provided in the C language. We will illustrate the most commonly used8 in the following sections.
The if statement allows branching within code and can be used to check if a particular condition has been met.
The equivalent of the if statement illustrated in the Figure 3 is:
The if-else statement allows one set of statements to be executed if the condition is met and an alternative set of statements ito be executed if the condition hasn’t been met.
The equivalent of the if-else statement illustrated in the Figure 4 is:
The third example of the if statement is the if-elseif-else statement which allows multiple conditions to be tested and blocks of statements to be executed for each decision.
The equivalent of the if-elseif-else statement illustrated in the Figure 5 is:
The equivalent of the switch statement illustrated in the Figure 6 is:
Statement;
switch (expression1) { // branch according to the value of the expression
case case_1 :
code_block_1;
break; // break is needed to avoid drop through to next case
case case_2 :
code_block_2;
break; // break is needed to avoid drop through to next case
case case_3 :
code_block_3;
break; // break is needed to avoid drop through to default case
// you can have any number of case statements
default : // optional
default_code_block;
}
Statement_2;
char student_grade = 'B';
printf("Your grade was %c: ",student_grade);
switch (student_grade)
{
case 'A':
printf ("excellent!\n");
break; // prevents fall-through to default
case 'B' :
printf("very good!\n");
break;
case 'C' :
printf("good!\n");
break;
case 'D' :
printf("satisfactory!\n");
break;
case 'E' :
printf("needs work!\n");
break;
case 'F' :
printf("sorry you failed!\n");
break;
default:
printf("Error! The grade %c is invalid\n",student_grade);
}
In order to write a function that loops, i.e. execution of a sequence of statements until a particular condition is met, a while statement can be used.
The while statement allows for a block of statements to be repeatedly executed as long as a condition is true.
The equivalent of the while statement illustrated in the Figure 7 is:
The do-while statement is almost identical to the while statement however the condition is checked after the statements have run.
The equivalent of the do-while statement illustrated in the Figure 8 is:
Another way of writing a while statement is to use a for loop.
The term loop is used for the execution of a sequence of statements until a particular condition is met.
The equivalent of the for statement illustrated in Figure 9 is:
Here is an actual for loop which solves the problem given in Lecture 3: Example 2.
It better illustrates how it might be written in a real program:
To execute this program see sum.c.
You can always write a for loop using while12.
The previous example could be written:
See sum with while.
The equivalent of the nested for statement illustrated in Figure 10 is:
See nested-counter for an executable example of this program.
In this section we have:
On the canvas course page, there is a series of short videos providing a history of the C language and a brief overview of programming paradigms as well as videos on functions and data type with a quiz to test your knowledge.
Please use the Course Question Board on Canvas or take advantage of the lecturers’ office hours.
Similarly to a function these variable names need to be declared before their use indicating their data type. More on this can be found in the self-directed study material for on Canvas for this week.
Please do not confuse =
in C with equality in mathematics. After assignment, the value in the variable can change. In mathematics \(a = b\) means that \(a\) is always equal to \(b\). If we change the value of \(b\), the value of \(a\) changes too. In C, a = b
copies the current value of b
into the storage assigned to a
. If we change the value of b
later, a
will not change. To confuse matters still further, there is another use of the equals symbol: ==
means is equal to and is used in decision statements such as is num1
equal to num2
?
We will see similar categories of operators when we come to look at assembly language. For example, for data transfer we have the register instructions LDI
(load register immediate), LDS
(load register from store), and STS
(store register to store).)
BODMAS is a mnemonic which stands for Backets, Operations, Division/Multiplication, Addition/Subtraction. It describes the order of calculation in an expression that involves operators. Brackets, which are considered first, are used to disambiguate expressions that would otherwise produce wrong results. For example a + b/c
is intrepreted as \(a + (b/c)\) not \((a + b)/c\).
An integer type means the value is a whole number (not a fractional number) that can be positive, negative, or zero.
The execution of expression 3.14 * r * r
would most likely result in a decimal (floating point) number. This would be truncated to an integer before it is assigned to b
. This is a common cause of mathematical error in programming.
Important: don’t confuse the double equals sign (==
) with =
. The latter is used for assignment operations. That is (x = 2)
is different from (x == 2)
.
Most of the unconditional branching statements such as goto
(for an unconditional branch to a label) and continue
(to ignore a condition without breaking out of a loop) are rarely used in modern programs. The break
statement is often used in switch statements and occasionally for breaking out of a loop when some exit condition is met.
Each case must be a constant expression: i.e. a number or a character.
i.e. avoids if
– elseif
– elseif
– elseif
– elseif
– … – else
in the C language a block is any sequence of statements surrounded by curly brackets { ... }
Indeed most c-compilers produce equivalent code for for and while.