====== Lab 06 - Structs and enums ======
===== Structs =====
* A struct groups variables under one name.
* Members can be of different types.
* Access with the dot operator (''.'') or arrow (''->'') if you have a pointer.
* Structs can be copied by value (unlike arrays!).
* ''sizeof(struct)'' may include padding bytes - compiler aligns fields for efficiency.
struct Point {
int x;
int y;
};
struct Point p = {10, 20};
printf("%d %d", p.x, p.y);
* Use ''typedef'' for convenience:
typedef struct {
char name[20];
int age;
} Person;
===== Unions =====
* All members share the same memory.
* Size = size of the largest member.
* Only one field is valid at a time.
* Writing to one member overwrites all others.
* Common in embedded systems or binary data parsing.
union Number {
int i;
float f;
char c;
};
union Number n;
n.f = 3.14;
printf("%f", n.f);
===== Enums =====
* Named integer constants for clarity.
* Default values start at 0, unless specified.
* Enum identifiers are just integers.
* You can assign any int, even if not in the enum (C does not check validity).
enum Color { RED, GREEN = 5, BLUE };
enum Color c = BLUE;
printf("%d\n", c); // prints 6
===== Bit Fields =====
* Compact representation of flags or small numbers inside structs.
* Specify number of bits per field.
* Bit-field ordering (left/right) is implementation-defined.
* Be careful mixing signed/unsigned types.
* Cannot take the address of a bit-field.
struct Status {
unsigned int power : 1;
unsigned int error : 1;
unsigned int mode : 2; // 0–3
};
===== Preprocessor =====
* Runs before compilation - simple text substitution.
* Compilers can set macros directly from the command line
* Use ''-E'' to see the preprocessor phase output or ''-S'' for assembly
* Common uses:
* ''#define'' macros
* ''#ifdef'', ''#ifndef'', ''#endif'' for conditional compilation
* ''#include'' for file inclusion
* Always parenthesize macro arguments:
#define SQUARE(x) ((x)*(x)) // OK
#define SQUARE(x) (x*x) // WRONG
#define PI 3.14159
#define SQUARE(x) ((x)*(x))
#define DEBUG
#ifdef DEBUG
printf("Debug mode on\n");
#endif
----
==== Task 1: Struct + Enum ====
Create a program that defines:
enum Department { IT, HR, SALES };
struct Employee {
char name[30];
int age;
enum Department dept;
};
* Read info for 3 employees from the user.
* Print them in a formatted table.
* Use a helper function ''const char* dept_to_str(enum Department d)'' to return department names.
==== Task 2: Union + Bit Fields ====
Define a union for storing a 32-bit register as either:
* an ''unsigned int raw;'' value, or
* a struct of bit fields showing:
struct {
unsigned int enable : 1;
unsigned int mode : 2;
unsigned int error : 1;
unsigned int reserved : 28;
};
Your program will:
* Allow user to enter a register value in hex (''0x...'')
* Print individual bit field values.
==== Task 3: Preprocessor + Conditional Compilation ====
Use a macro for debug control:
#define DEBUG 1
* Wrap debug `printf()` statements in ''#ifdef DEBUG''
* Print a message like:
#ifdef DEBUG
printf("[DEBUG] Value = %d\n", x);
#endif
* Try compiling after commenting out `#define DEBUG` or modifying the code to print debug messages only when the compiler defines the macro.