Preprocessor Directives
Preprocessor Directives tell the Preprocessor to perform specific actions:
#include: Copy the contents of the included file into this source file…
#define: Create a Macro… token-string substitution…
#undef: Removes a name previously created by #define
#if: Controls conditional compilation…
#elif: Controls conditional compilation…
#else: Controls conditional compilation…
#endif: The closing directive for #if conditional compilation…
#ifdef: Check if a token has been defined… same as #if defined
#ifndef: Check if a token has not been defined… aka #if !defined
How the #include directive works:
Now the build process outputs a .i file as a result of the preprocessing stage
Macro Definition
The #define directive creates a Preprocessor Macro
Historically, C programmers often used #define to declare constant values (avoid magic numbers)
In this example, Anywhere SIZE appears in the source code file the Preprocessor replaces SIZE with 10.
Function-like Macros (use this macro to performance function)
Performance the (x *57.29578f) for the label RADTODEG
Handle the Visual Studio Warning: C4996
If you scroll across on the warning… the compiler reminds you to use: _CRT_SECURE_NO_WARNINGS
You just have to remember to put it at the top with #define first
If you see this warning, you will need to add:
#define _CRT_SECURE_NO_WARNINGS
at the very top of your source code, on line 1… before the #include <stdio.h>
must #define _CRT_SECURE_NO_WARNINGS for all future exercises
Conditional Compilation (Test if a macro is defined)
It is possible to choose parts of a program to compile depending on what Macro tokens are defined
Special Macro Directives
There are built-in Preprocessor Macro Directives…
__FILE__: The name of the current source file…
Expands to be a string literal…
__LINE__: The line number in the current source file…
This is a decimal integer…
__DATE__: The compilation date of the current source file…
A string literal in the form of: Mmm dd yyyy.
__TIME__: The compliation time of the current source file…
A string literal in the form of: hh:mm:ss.
Example:
Other Preprocessor Features:
Assert: #include <assert.h>
A header file in the standard library of the C programming language…
#include <assert.h>
Defines: assert ()
The programmer can use this to verify assumptions
If the assumption expression evaluates to false, a programmer focused diagnostic message will be printed
The assert () function allows the program to check that the state of their program makes sense at a particular moment in the program’s execution
For example:
Is a variable negative at this moment? It shouldn’t be…
Has a certain number of items been counted at this point in time?...
Is a pointer null at this moment? It shouldn’t be
If the condition passed into the assert () function evaluates to be true, the program continues running
If the condition passed into the assert () function evaluates to be false, assert causes a breakpoint to trigger…
When the assert breakpoint occurs… it is then the programmer’s responsibility to discover why the sanity check has failed!
Debugging… Watch Window… Stepping
Was it a good assumption in the first place?
The assert function is used to check the state of data as the program executes:
This program will execute normally… the assert will evaluate to true… and the program will continue executing
The programmer’s assumption that x is 50at that point in the program is true
Macro Definition: asser t()
assert is actually a preprocessor macro
Design by Contract (Pre and Post Conditions)
Design by Contract is a software correctness methodology
It documents pre-conditions and post-conditions that reflect the change state in state of a program as it is executed…
Pre-conditions:
Something that must always be true prior to executing some code…
Post-conditions:
Something that must always be true after executing some code…
But when the hours == 25; minutes == 61, it will be wrong! As the function cannot check if the input is right.
Using Design by Contract, a function can be design such that the programmer must call the function with data in a particular state…
•
Assert can be used to ensure the caller provides arguments that are in an acceptable state for print_time to use
assert can be used to ensure the is returning data in an acceptable state for the caller to use
Assert and Pointers
It is more desirable to trigger the assert, and hence have a programmer discover the issue, than allow the pointer to be dereferenced and cause a runtime crash
Visual Studio: Build Target
And the Release .exe is also stored here
The asserts are removed from the Release build target
None of the sanity checks occur in a Release build
The program can then run faster as a Release executable…
But… if there is an accidental side effect in an assert…
Then the behavior of the program’s Release build will be different to the behavior of the Debug build!
Asserts should never cause state changes… only check state
Coding Standards (Commenting for functions)