In this module, we will review concepts around C-programming. We'll do a quick review of C-Programing concepts with examples to re-familiarize you with the syntax. This also serves as the minimum expected knowledges of C-programming before coming into the course. You will recall that embedded systems primarily use C-programming, however, we have a specific flavor of C for this application class called Embedded C. Embedded C focuses on some certain features that are extremely relevant to low-level design. However, Embedded C and C program are still the same language. Declaring variables in C programs requires a specific format with many fields. You start declaring a variable by providing type qualifiers and type modifiers, and the data type, a unique variable name, and potentially an initial value. In C-programming, only one piece of data may be assigned at a time and that must always be on the left side of an assignment operator, each line will end with a semicolon. But data types can be chosen from a variety of options and can describe a specific variable. These include integer types, floating point types, enumerated types, derived types, and void types. Type modifiers are used to increase the size of these types or change the properties of the variables. These include short, long, unsigned, or signed. Type qualifiers are used to provide specific instructions to the compiler on how the variable should be managed. Const is one example and we will skip the others until later in the course. Data is stored in memory as a series of bits where 8 bits equal 1 byte. Here is a table of typical sizes of data types reflected in bytes. You should know that the types are actually architecture-dependent, and the C standard specifies minimum sizes for the data types. You can see that the int type show two different sizes on this table. The data in memory expressed in bits is represented in software using the binary number system. Oftentimes, we use hexadecimal, base 16 interchangeably for simplicity. There are three different categories of numbers we usually are interested in working with C-programming. Those are unsigned numbers, signed numbers, and fractional numbers. The most simple are unsigned numbers which are just positive binary numbers. Translation between decimal and unsigned binary can be done very simply because unsigned numbers use a positional number system representation to express value. Each position represents a value and a magnitude. Sign numbers are represented with the two's complement form. The conversion of sign numbers is a little more complex because they split the numbers of unique binary combinations in half. One half for your positive number set and the other one for your negative set. The positive bit mappings look just like unsigned numbers with a zero in the most significant position. The negatives are represented with a one in the most significant position, the base value represents a very large negative number. Lastly, fractional numbers can be represented with fixed point or floating point representations. This will be covered later in the course. Embedded applications will favor the use of binary and hexadecimal for firmware as well as both signed and unsigned number representations. Data is assigned and manipulated using a variety of operators. There are multiple types of operators which include logical, bitwise, arithmetic, and relational. Logical operators perform on a conditional basis. Meaning only if the expression before and after the operators are logically true. They consist of AND, OR, and NOT. Know that logical AND, OR conditions are expressed in pairs and are usually used in conditional blocks, such as if-else statements or while statements. Bitwise operators are logic operators that operate on an individual bit basis instead of a full expression, but these two types of operators are not the same. The bitwise operators include right and left shifts, OR, AND, EXOR, and a one's complement or a bitwise invert. When two data types are operated on with a bitwise expression, each corresponding bit of the two numbers get the logical expression applied to one another. For instance, two variables called varA and varB initialized to arbitrary values are bitwise ANDed. Bit seven of varA gets bitwise operated on with bits seven of varB and no other bit positions. Arithmetic operators perform your typical math operations, such as add, subtract, multiply, divide, increment, decrement, and modulus. The modulus operator is the remainder operator and increment and decrement can be done before or after the data access. Also, bitwise and arithmetic operators can be combined with an assignment operator for simple expressions. Relational operators are similar to logical operators used for Boolean expressions in conditional blocks. This check for things like less than, less than or equal to, greater than, greater than or equal to, exactly equal to, and not equal to. You can control the flow of a program with the use of conditional blocks. This allows software blocks to be turned on and off at runtime based on a Boolean expression that may or may not use logical operators or relational operators. These blocks include many variations on the if statement with the if, else if, and else statements, as well as the switch statement. A more advanced control statement is called the loop, which allows a block of code to be repeated based on a condition. These vary on pre or post loop checks. These loops are a for loop, a while loop, and a do while loop. If the programmer wishes to interrupt the default flow of loop statements, they can use either the break keyword, which causes an immediate exit from the inner most loop, or the continue statement, which skips the remainder of the current loop body and proceeds to the next iteration. Functions are small blocks of code used to organize a software idea that takes in a list of parameters and can return a piece of data. These use the same types that were discussed before. Functions require both a declaration and a definition. The declaration or function prototype specifies the function type, a unique name, and the parameter list. The function definition mimics a copy of the function declaration, but it also includes the contents or definition of the function body. Typically, header files or.h files contain public function declarations while implementation files,.c files, contain private function declarations and all the function definitions. Function parameters are passed in by value, this means a copy is made and that copies only accessible in the function. However, an alternative to this is passing any a pointer to a function. The pointer variable itself is passed in by value as a new pointer copy is made. However, passing a parameter by pointer allows the original data at the address the pointer holds to be changed. This is referred to as passing by reference. Variables declared with any function are said to have a local scope and are only accessible by the inside of the function. Variables declared outside are declared externally to functions are described as global variables or global scope. One last concept we will cover is pointers. Pointers are special data types that hold address information. There are three operators that we use with respect to doing pointer variables. The first is the declaration. We use a pointer star and a variable declaration to specify a data type is a pointer. The address of operator is used to assign other variables that have been declared their addresses to pointer variables. The pointer dereference star, which is used after a pointer declaration, is used to dereference a point in memory. In this case, to dereference, you put the star in front of the variable, and this gives you the contents of that address. This address information can be treated like data but is actually a reference point to memory. Pointers or addresses can be manipulated like data to change the address to different locations without actually changing the data of those locations. Pointers must be set to a valid address before you can access that data, and you must dereference a pointer to access the actual memory to change it or modify it. Note that the pointer type does not affect the address or the pointer variable itself. The pointer type is used in the dereference operation to specify how much data you want to access at that address location. So, the size of a pointer variable is the exact same size in all other pointer variable declarations. On the other hand, the size of different data types and variables declared with those different types may not be the same size. Also, the size of pointer variables once dereferenced may or may not be the same size as they are referencing a dereference piece of memory. Typically, your code starts with main and this represents your topmost scope. Main can call many subfunctions. You want to split up your code into both functions and multiple files for modularity and maintainability. Those files can easily reference other code by using the include directive to include other header files. Many of the concepts discussed in this review are very introductory to C-programming. You may have experienced in other languages that help with transition to see easy as you take time learning at syntax. However, understanding these basic features is going to be completely necessary before we move into the specialized coding needed for embedded software. Here's a short demo that shows many of these features in a simple C program. The goal of this program is to perform some data analytics on a set of numbers stored in an array. We start by looking at the top of this file, which has some comments and file documentation. Next, we have some function declarations and constant definitions. Immediately following these, we have our main function. Main starts with the creation of variables, an array is declared and initialized to some arbitrary values. Next, some variables are created for tracking statistics and loop iterations. Following the variable declarations is a section of code that does the analysis on this array. This analysis includes finding the average, maximum, and minimum, as well as it creates a histogram of the data. The first statistic is calculated with a function to calculate the average. Both integer and pointer parameters are passed into this function and the average is returned. Inside this function or conditional statements and a for loop. Next, you see a while loop, which is used to iterate on the data array for calculating the minimum and maximum. Conditional statements are used to make decisions based on the data set for the minimum and maximum values, then the histogram is updated. Once the full set is processed, the loop exits and the program exits.