โ๏ธ 15. Preprocessor & Header Files
Before the C compiler translates your program into machine code, another stage can process special instructions called preprocessing directives.
These directives begin with the character #.
#include <stdio.h>
#define MAX 100 These directives affect the source before the resulting C statements are compiled. They are not instructions that run each time the program executes.
15.1 What Is the C Preprocessor?
The preprocessor handles directives and macro expansion before the compiler translates the resulting C code. For example, it can replace a symbolic limit with its defined value.
Common directives include:
#include#define#undef#if#ifdef#ifndef#elif#else#endif#error#line#pragma
15.2 Where Does the Preprocessor Fit?
C Source File โ โผ Preprocessing โ โผ Translation / Compilation โ โผ Object Code โ โผ Linking โ โผ Executable Program
For learning purposes, it is useful to think of preprocessing as the stage that handles directives such as #include and #define before the compiler translates the resulting source.
15.3 Preprocessor Directive Basics
A directive normally begins with #.
#define VALUE 10 The directive is recognized by the preprocessing stage.
Unlike an ordinary C statement, it does not require a semicolon at the end.
#include <stdio.h>
#define MAX 100 #define MAX 100; when you intend MAX to represent the token sequence 100. The semicolon would become part of the macro replacement. 15.4 #include
The #include directive brings the named headerโs contents into the source being processed. The header can supply the declarations needed by the code that follows.
#include <stdio.h> This is why a program can use declarations associated with standard input/output facilities such as printf and scanf.
#include does not call a function. It is a preprocessing directive. 15.5 <...> vs "..."
Two common forms are:
#include <stdio.h>
#include "myheader.h" Angle brackets are normally used for standard or library headers, while quotes are normally used for project headers. The compilerโs documented search paths determine where each form looks.
<header.h>
Commonly used for library/system headers.
"header.h"
Used for project headers. Compilers commonly search near the including file before trying other configured locations.
15.6 What Is a Header File?
A header file commonly contains declarations, type definitions, macros and other information intended to be shared by multiple source files.
Examples from the C standard library include:
stdio.hโ input/output facilitiesstdlib.hโ general utilitiesstring.hโ string handlingmath.hโ mathematics functionsctype.hโ character classificationtime.hโ date and time facilitieslimits.hโ integer limitsfloat.hโ floating-point characteristics
15.7 #define
The #define directive defines a macro.
#define MAX_MARKS 100 When an eligible macro name appears later, its replacement tokens are inserted. Macro names inside string literals are not replaced as ordinary identifiers.
#include <stdio.h>
#define MAX_MARKS 100
int main(void)
{
printf("%d\n", MAX_MARKS);
return 0;
} Conceptually, the preprocessor produces source equivalent to:
printf("%d\n", 100); 15.8 Object-Like Macros
A macro without parameters is commonly called an object-like macro.
#define PI 3.14159265358979323846
#define MAX_SIZE 100
#define COMPANY_NAME "CodeBhavya" These macros replace the identifier with their replacement token sequence.
Good use
Compile-time constants, feature flags and short configuration values.
Alternative
For typed constant values, const is useful when you want a typed object. In C17, a const int is not generally an integer constant expression for uses such as a case label, so it does not replace every use of a macro or enumerator.
15.9 Function-Like Macros
A function-like macro has parameters.
#define SQUARE(x) ((x) * (x)) Example:
int result = SQUARE(5); Conceptually becomes:
int result = ((5) * (5)); 15.10 Why Macro Parentheses Matter
Consider this unsafe macro:
#define SQUARE(x) x * x Now:
SQUARE(2 + 3) can become:
2 + 3 * 2 + 3 which is not the intended mathematical grouping.
Prefer:
#define SQUARE(x) ((x) * (x)) Macro โ โผ Token substitution โ โผ Operator precedence still applies โ โผ Parentheses protect the intended expression
15.11 Macro Side Effects
Parentheses protect grouping, but a macro can still use an argument twice. Be careful with an argument that changes a variable, such as i++.
#define SQUARE(x) ((x) * (x)) Consider:
int i = 3; int result = SQUARE(i++); The macro expansion contains two occurrences of i++. In this multiplication, the changes to i are unsequenced, so the expression has undefined behavior. Do not run it and treat one compilerโs output as a valid answer.
15.12 Macro vs Function
| Feature | Macro | Function |
|---|---|---|
| Handled as | Preprocessing token replacement | Normal C function semantics |
| Type checking | No function-parameter type checking | Compiler can check parameter types from declarations |
| Argument evaluation | May occur multiple times | Arguments are evaluated for the call according to C rules |
| Debugging | Can be harder to inspect | Usually easier to debug as a function |
| Recursion | Not a normal recursive function mechanism | Functions can be recursive |
15.13 #undef
The #undef directive removes a macro definition.
#define LIMIT 100
#undef LIMIT After #undef, the macro name is no longer defined by that macro definition.
#undef does not erase an ordinary variable. It operates on a macro definition. 15.14 Conditional Compilation
Conditional compilation chooses source code before the program runs. This differs from an if statement, which chooses a path while the compiled program is running.
#if CONDITION
/* selected source */
#endif If the condition evaluates to nonzero after preprocessing, the controlled section is included.
Example
#define DEBUG 1
#if DEBUG
printf("Debug mode\n");
#endif Because DEBUG expands to 1, the controlled section is included.
15.15 #if, #elif and #else
#define LEVEL 2
#if LEVEL == 1
/* beginner */
#elif LEVEL == 2
/* intermediate */
#else
/* other */
#endif The preprocessor selects one appropriate branch.
#if โ โโโ condition true โ โ โ include branch โ โโโ condition false โ #elif? โ โโโ true โ include branch โ โโโ false โ continue โ #else
15.16 #ifdef
#ifdef tests whether a macro is defined.
#define DEBUG
#ifdef DEBUG
printf("Debugging enabled\n");
#endif The value of the macro is not the point here. The test asks whether the macro name is defined.
#ifdef DEBUG means: โHas a macro named DEBUG been defined?โ 15.17 #ifndef
#ifndef tests whether a macro is not defined.
#ifndef MAX_SIZE
#define MAX_SIZE 100
#endif This pattern is especially important for protecting header files from repeated inclusion.
15.18 Header Include Guards
If two headers both include the same project header, its definitions could be seen twice. A guard macro makes the second inclusion skip the guarded contents within that translation unit.
#ifndef STUDENT_H
#define STUDENT_H
struct Student { int id; int marks; };
void displayStudent(struct Student s);
#endif First inclusion โ โผ STUDENT_H not defined โ โผ Define STUDENT_H โ โผ Process header contents Second inclusion โ โผ STUDENT_H already defined โ โผ Skip contents
15.19 How Project Header Files Work
A larger C project can separate declarations and implementations.
student.h
#ifndef STUDENT_H
#define STUDENT_H
struct Student {
int id;
int marks;
};
void displayStudent(struct Student s);
#endif student.c
#include <stdio.h>
#include "student.h"
void displayStudent(struct Student s)
{
printf("ID = %d\n", s.id);
printf("Marks = %d\n", s.marks);
} main.c
#include "student.h"
int main(void)
{
struct Student s = {101, 90};
displayStudent(s);
return 0;
} 15.20 Predefined Macros
C implementations provide several predefined macros. Common examples include:
__FILE__ __LINE__ __DATE__ __TIME__ __STDC__ __STDC_VERSION__ Their meanings are useful for diagnostics and implementation/language-version information, although availability and exact predefined macro set can depend on the language standard and implementation.
Example
#include <stdio.h>
int main(void)
{
printf("File: %s\n", __FILE__);
printf("Line: %d\n", __LINE__);
return 0;
} __FILE__ identifies the source file and __LINE__ identifies the current source line in the preprocessing context.
15.21 __STDC_VERSION__
When provided by a conforming implementation for the applicable standard mode, __STDC_VERSION__ can be used to identify the C language standard version.
#include <stdio.h>
int main(void)
{
#ifdef __STDC_VERSION__
printf("C standard version: %ld\n", (long)__STDC_VERSION__);
#else
printf("C standard version macro not available\n");
#endif
return 0;
} 15.22 #error
The #error directive requests a diagnostic containing the specified preprocessing tokens.
#ifndef REQUIRED_FEATURE
#error "Required feature is not enabled"
#endif Use it for an unsupported configuration so the compiler reports the problem during translation, before a program is run.
15.23 #pragma
#pragma provides implementation-defined instructions to the compiler.
#pragma The actual effect depends on the compiler and platform.
#pragma is supported by every compiler. Check the compilerโs documentation before relying on a particular pragma. 15.24 #line
The #line directive changes the logical line number and optionally the filename used in later diagnostics and predefined macros. It does not move execution to another line.
#line 100 "generated.c" This is primarily useful in generated source and specialized tooling.
15.25 Program Tracing: Macro Replacement
#define BONUS 10
int main(void)
{
int marks = 80;
marks = marks + BONUS;
return 0;
} Original source marks = marks + BONUS; โ โผ Macro replacement โ โผ marks = marks + 10; โ โผ Compiler processes resulting source
The macro does not create a runtime variable called BONUS.
15.26 Program Tracing: Conditional Compilation
#define MODE 2
#if MODE == 1
printf("Basic");
#elif MODE == 2
printf("Advanced");
#else
printf("Unknown");
#endif MODE โ โผ 2 โ โผ #if MODE == 1 โ โโโ false #elif MODE == 2 โ โโโ true โ โผ printf("Advanced"); #else Skipped The non-selected source branches are excluded from the resulting translation unit.
15.27 Program Tracing: Include Guard
#ifndef CONFIG_H
#define CONFIG_H
#define MAX_USERS 100
#endif Include config.h โ โผ Is CONFIG_H defined? โ โโโโโดโโโโโ โ โ No Yes โ โ โผ โผ Define Skip CONFIG_H contents โ โผ Process header
15.28 Macro Stringification โ Preview
Function-like macros can use # in a replacement list to convert a macro argument into a string literal.
#define SHOW_NAME(x) #x For example:
SHOW_NAME(CodeBhavya) produces a string-literal representation equivalent to:
"CodeBhavya" # character used to start a preprocessing directive. 15.29 Token Pasting ## โ Preview
The ## operator in a macro replacement list combines preprocessing tokens.
#define JOIN(a, b) a##b For example:
JOIN(total, 1) can form the preprocessing token:
total1 15.30 Common Mistakes
Mistake 1 โ Adding a semicolon to a macro value
#define MAX 100; The semicolon becomes part of the macro replacement.
Prefer:
#define MAX 100 Mistake 2 โ Unsafe function-like macro
#define SQUARE(x) x * x Use proper parentheses:
#define SQUARE(x) ((x) * (x)) Mistake 3 โ Forgetting include guards
Repeated inclusion can repeat type definitions or other declarations. Put a distinct include guard around a project headerโs contents.
Mistake 4 โ Confusing #ifdef with value testing
#ifdef FLAG asks whether FLAG is defined. It does not ask whether its replacement value is nonzero.
Mistake 5 โ Using -> or . incorrectly in macro code
Preprocessor substitution does not change C's normal operator rules. After expansion, the resulting source must still be valid C.
15.31 Common Confusions
| Confusion | Correct Understanding |
|---|---|
#include is a function | It is a preprocessing directive. |
#define creates a variable | It defines a macro. |
| Macro and function are identical | Macros are preprocessing substitutions; functions have normal C call semantics. |
#ifdef X checks whether X equals 1 | It checks whether macro X is defined. |
| Header file is the compiled library | A header supplies source-level declarations, definitions of macros/types, etc.; library linkage is a separate concern. |
sizeof can be used in preprocessing | Preprocessing conditions do not generally evaluate arbitrary C expressions such as sizeof. |
15.32 Complete Program: Macro + Conditional Compilation
#include <stdio.h>
#define PASS_MARKS 40
#define DEBUG
int main(void)
{
int marks = 75;
#ifdef DEBUG
printf("Checking marks...\n");
#endif
if (marks >= PASS_MARKS) {
printf("Pass\n");
} else {
printf("Fail\n");
}
return 0;
} Trace
stdio.his included.PASS_MARKSis defined as40.DEBUGis defined.- The
#ifdef DEBUGblock is included. PASS_MARKSis replaced by its macro replacement.- The resulting C source is compiled normally.
15.33 Good Header File Design
A useful project header should expose information that other source files need.
For example:
#ifndef CALCULATOR_H
#define CALCULATOR_H
int add(int a, int b);
int subtract(int a, int b);
#endif The implementation can remain in a source file:
#include "calculator.h"
int add(int a, int b)
{
return a + b;
}
int subtract(int a, int b)
{
return a - b;
} 15.34 Placement-Important Macro Patterns
#define MAX(a, b) ((a) > (b) ? (a) : (b)) This demonstrates parentheses around both parameters and the complete replacement expression.
However, repeated evaluation is still possible:
MAX(i++, j++) Therefore macros should be designed carefully.
Remember
Parenthesize macro parameters.
Remember
Parenthesize the complete expression.
Remember
Watch for repeated evaluation and side effects.
Remember
Use functions when normal function semantics are more appropriate.
15.35 The _Generic Selection Expression (C11)
_Generic is a C11 selection expression, not a preprocessing directive. It chooses a listed expression using the type of its controlling expression. That controlling expression is not evaluated, so using it for type selection does not perform its side effects.
Complete C program:
#include <stdio.h>
#define TYPE_NAME(x) _Generic((x), int: "int", double: "double", default: "other")
int main(void)
{
printf("%s\n", TYPE_NAME(5));
printf("%s\n", TYPE_NAME(2.5));
return 0;
}
Expected output:
int
double
Step-by-step explanation:
- The integer constant 5 selects the int association.
- The floating literal 2.5 has type double and selects that association.
- default is chosen for any type without a matching association.
15.36 Quick Revision
๐ #include โ Includes a file.
๐ #define โ Defines a macro.
๐ #undef โ Removes a macro.
๐ #if โ Conditional compilation.
๐ #ifdef โ Macro is defined.
๐ #ifndef โ Macro is not defined.
๐ #else โ Alternative condition.
๐ #elif โ Additional condition.
๐ #endif โ Ends conditional block.
๐ Header guard โ Prevents repeated inclusion.
๐ฌ Preprocessor โ Source Transformation Flow
Follow what happens to directives before ordinary C execution begins.
๐ฌ C Preprocessing Visualizer
Each active card represents one major preprocessing stage.
๐ Program Tracing โ Preprocessor & Header Files
Trace the runtime program after macro expansion and conditional compilation have already taken effect.
โ
15.37 Quick MCQs
Select an answer first, then click Check Answer. A correct choice becomes green. If the answer is wrong, your choice becomes red and the correct option becomes green. The explanation appears below.
Preprocessor directives begin with the # symbol.
#include requests inclusion of a header or source file according to preprocessing rules.
#define creates an object-like or function-like macro.
#undef removes the current definition of a macro name.
#ifdef NAME conditionally includes code when NAME is defined as a macro.
#ifndef NAME conditionally includes code when NAME is not defined.
The declaration of printf() is provided by stdio.h.
#endif closes conditional preprocessing blocks such as #if, #ifdef, and #ifndef.
15.38 ๐ฏ Practice Problems
Practice macros, conditional compilation, header-style declarations, predefined macros, include guards, and project organization. Use ๐ป Solve It Yourself first, open Hint only when needed, and use Show Program after attempting the problem.
Problem 1: Define a macro PI and calculate the area of a circle.
Input: Radius as a floating-point number.
Output: Print the area to two decimal places.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define PI 3.14159
int main()
{
double radius;
scanf("%lf", &radius);
printf("%.2f", PI * radius * radius);
return 0;
}
Problem 2: Create a macro to calculate the square of an integer.
Input: One integer.
Output: Print its square.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define SQUARE(x) ((x) * (x))
int main()
{
int n;
scanf("%d", &n);
printf("%d", SQUARE(n));
return 0;
}
Problem 3: Create a macro to find the maximum of two integers.
Input: Two integers.
Output: Print the larger value.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
int main()
{
int a, b;
scanf("%d %d", &a, &b);
printf("%d", MAX(a, b));
return 0;
}
Problem 4: Create a macro to find the minimum of two integers.
Input: Two integers.
Output: Print the smaller value.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
int main()
{
int a, b;
scanf("%d %d", &a, &b);
printf("%d", MIN(a, b));
return 0;
}
Problem 5: Create a macro to calculate the cube of an integer.
Input: One integer.
Output: Print its cube.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define CUBE(x) ((x) * (x) * (x))
int main()
{
int n;
scanf("%d", &n);
printf("%d", CUBE(n));
return 0;
}
Problem 6: Use #undef to remove a macro definition and then define the same name with a new value.
Input: No input.
Output: Print the new macro value.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define VALUE 10
#undef VALUE
#define VALUE 20
int main()
{
printf("%d", VALUE);
return 0;
}
Problem 7: Use #ifdef to check whether DEBUG is defined.
Input: No input.
Output: Print "Debug Enabled".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define DEBUG
int main()
{
#ifdef DEBUG
printf("Debug Enabled");
#else
printf("Debug Disabled");
#endif
return 0;
}
Problem 8: Use #ifndef to compile a block only when FEATURE is not defined.
Input: No input.
Output: Print "Feature Not Defined".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
#ifndef FEATURE
printf("Feature Not Defined");
#else
printf("Feature Defined");
#endif
return 0;
}
Problem 9: Use #if and #else to select between two versions of a program.
Input: No input.
Output: Print "Version 2".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define VERSION 2
int main()
{
#if VERSION == 2
printf("Version 2");
#else
printf("Version 1");
#endif
return 0;
}
Problem 10: Use #elif to select among three program modes.
Input: No input.
Output: Print "Mode 3".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define MODE 3
int main()
{
#if MODE == 1
printf("Mode 1");
#elif MODE == 2
printf("Mode 2");
#else
printf("Mode 3");
#endif
return 0;
}
Problem 11: Create a header-style declaration for add() and use the function in a program.
Input: Two integers.
Output: Print their sum.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int add(int a, int b);
int main()
{
int a, b;
scanf("%d %d", &a, &b);
printf("%d", add(a, b));
return 0;
}
int add(int a, int b)
{
return a + b;
}
Problem 12: Create reusable mathematical constants with macros and use them in a calculation.
Input: One floating-point radius.
Output: Print circle circumference to two decimal places.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define PI 3.14159
int main()
{
double r;
scanf("%lf", &r);
printf("%.2f", 2.0 * PI * r);
return 0;
}
Problem 13: Create a header-style declaration for a string utility function that counts vowels.
Input: One word.
Output: Print the number of vowels.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int countVowels(const char text[]);
int main()
{
char text[100];
scanf("%99s", text);
printf("%d", countVowels(text));
return 0;
}
int countVowels(const char text[])
{
int count = 0;
for (int i = 0; text[i] != '\0'; i++)
{
char ch = text[i];
if (ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u' ||
ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U')
{
count++;
}
}
return count;
}
Problem 14: Create a header-style declaration protected by a traditional include guard and use the declared function.
Input: Two integers.
Output: Print their product.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#ifndef MATHUTILS_H
#define MATHUTILS_H
int multiply(int a, int b);
#endif
int main()
{
int a, b;
scanf("%d %d", &a, &b);
printf("%d", multiply(a, b));
return 0;
}
int multiply(int a, int b)
{
return a * b;
}
Problem 15: Create a program that displays __FILE__ and __LINE__ using a controlled #line directive.
Input: No input.
Output: Print "codebhavya.c 500".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
#line 500 "codebhavya.c"
printf("%s %d", __FILE__, __LINE__);
return 0;
}
Problem 16: Use the predefined __DATE__ and __TIME__ macros and verify their standard string sizes.
Input: No input.
Output: Print the sizes of the two string literals, including their null terminators.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
int main()
{
printf("%zu %zu", sizeof(__DATE__), sizeof(__TIME__));
return 0;
}
Problem 17: Create a macro that calculates the absolute value of an integer.
Input: One integer, excluding the minimum representable int.
Output: Print its absolute value.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define ABS(x) (((x) < 0) ? -(x) : (x))
int main()
{
int n;
scanf("%d", &n);
printf("%d", ABS(n));
return 0;
}
Problem 18: Create a macro to check whether an integer is even.
Input: One integer.
Output: Print "Even" or "Odd".
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define IS_EVEN(x) (((x) % 2) == 0)
int main()
{
int n;
scanf("%d", &n);
printf("%s", IS_EVEN(n) ? "Even" : "Odd");
return 0;
}
Problem 19: Demonstrate a square macro and an equivalent square function on the same input.
Input: One integer.
Output: Print the macro result and function result.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
#define SQUARE_MACRO(x) ((x) * (x))
int squareFunction(int x)
{
return x * x;
}
int main()
{
int n;
scanf("%d", &n);
printf("%d %d", SQUARE_MACRO(n), squareFunction(n));
return 0;
}
Problem 20: Model a small .h + .c + main.c project by separating declarations, implementations, and main() sections in one runnable file.
Input: Two integers.
Output: Print their sum and difference on separate lines.
C Code Editor
Sample Input
Program Output
Run your program to see the output.
Test Cases
#include <stdio.h>
/* mathutils.h */
int add(int a, int b);
int subtract(int a, int b);
/* mathutils.c */
int add(int a, int b)
{
return a + b;
}
int subtract(int a, int b)
{
return a - b;
}
/* main.c */
int main()
{
int a, b;
scanf("%d %d", &a, &b);
printf("%d\n", add(a, b));
printf("%d", subtract(a, b));
return 0;
}
15.39 Key Takeaway
#include โ Include files
#define โ Define macros
#undef โ Remove macros
#ifdef โ If macro is defined
#ifndef โ If macro is not defined
#if / #elif / #else โ Conditional compilation
#endif โ End conditional block
Header guards โ Prevent repeated inclusion
๐ค Preprocessor & Header Files โ Interview Questions
๐ก Preprocessor & Header Files โ Placement Tips
- For function-like macros, parenthesize both each parameter and the entire replacement expression.
- Avoid passing expressions with side effects such as
i++to macros that use the same parameter more than once. - Use header guards in reusable project headers to prevent repeated declarations caused by multiple inclusion paths.
- Keep declarations and shared interfaces in header files; keep function definitions in source files unless there is a specific reason otherwise.
- Use conditional compilation for build-time choices such as debugging code or platform-specific sections.
- Remember that preprocessing happens before runtime, so
#ifcannot directly test a normal runtime variable.
โ๏ธ Preprocessor & Header Files โ Extra Practice Questions
- Create a macro that returns the smaller of three values without using a function.
- Create a DEBUG macro that enables extra diagnostic output only in debug builds.
- Write a header guard for a hypothetical
student.hheader containing a structure declaration and function prototypes. - Use nested
#ifdirectives to select code based on two compile-time configuration macros. - Experiment with
#lineand observe how it changes__FILE__and__LINE__. - Create a three-file calculator project consisting of
calculator.h,calculator.c, andmain.c.