Skip to content

Define, Macros, Struct, Union in C

In C and C++, #define is a preprocessor directive used to create symbolic constants or macros. Here’s a comprehensive guide on #define:

#define NAME value
  • NAME: Symbolic name or macro name.
  • value: Value or expression associated with the name.

Defining Constants

Define constants using #define to avoid magic numbers in your code.

#define PI 3.14159
#define MAX_BUFFER_SIZE 1024
  • Usage:
#include <stdio.h>
#define PI 3.14159
int main() {
printf("Value of PI: %f\n", PI);
return 0;
}

Defining Macros

Define macros for code snippets or reusable code segments.

#define SQUARE(x) ((x) * (x))
  • Usage:
#include <stdio.h>
#define SQUARE(x) ((x) * (x))
int main() {
int num = 5;
printf("Square of %d is %d\n", num, SQUARE(num));
return 0;
}

Note: Use parentheses around parameters and the entire macro definition to avoid unexpected results due to operator precedence.

Use #define for conditional compilation to include or exclude code based on conditions.

#define DEBUG
#ifdef DEBUG
printf("Debug mode is enabled.\n");
#endif
  • #ifdef: Checks if DEBUG is defined.
  • #ifndef: Checks if DEBUG is not defined.
  • #endif: Ends the conditional block.

Use #undef to undefine a macro if it is no longer needed.

#define MAX_SIZE 100
#undef MAX_SIZE
#define MAX_SIZE 200

For macros with multiple statements, use braces to group them:

#define PRINT_DEBUG_INFO() \
{ \
printf("Debug info\n"); \
// More debug code \
}
  • Usage:
#include <stdio.h>
#define PRINT_DEBUG_INFO() \
{ \
printf("Debug info\n"); \
/* Additional debug code */ \
}
int main() {
PRINT_DEBUG_INFO();
return 0;
}

You can create macros with arguments to generalize functionality:

#define ADD(x, y) ((x) + (y))
  • Usage:
#include <stdio.h>
#define ADD(x, y) ((x) + (y))
int main() {
int a = 5, b = 10;
printf("Sum: %d\n", ADD(a, b));
return 0;
}
  • #include: Includes a file.
  • #ifdef, #ifndef: Conditional compilation.
  • #define, #undef: Define and undefine macros.
  • Avoid Overuse: Use const or enum for constants in C++ where possible. Macros are less type-safe.
  • Use Namespaces: In C++, consider using namespace for constants and functions.
  • Limit Side Effects: Ensure macros don’t introduce unintended side effects by using parentheses and carefully designing macro logic.
  • #define is used for defining constants and macros.
  • #define NAME value: Defines a symbolic name.
  • #define MACRO(x) expression: Defines a macro with parameters.
  • #ifdef, #ifndef: Control conditional compilation.
  • #undef: Undefine a macro.
  • Best Practices: Use macros judiciously and prefer modern alternatives in C++.

Using #define effectively can make your code more readable and maintainable by avoiding hardcoded values and making reusable code segments.


Structures (struct) and unions (union) are used in C and C++ to group variables of different types into a single unit. They are both user-defined data types but have different properties and uses.

A struct (short for “structure”) is a composite data type that groups variables of different types under a single name.

Definition:

struct Person {
char name[50];
int age;
float height;
};

Key Points:

  • Memory Allocation: Each member of a struct is allocated its own memory space. The total size of the struct is the sum of the sizes of its members plus any padding for alignment.

  • Accessing Members: Members are accessed using the dot operator (.) for a structure variable.

  • Initialization:

    struct Person person1 = {"Alice", 30, 5.6};

Example Usage:

#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person person1 = {"Alice", 30, 5.6};
printf("Name: %s\n", person1.name);
printf("Age: %d\n", person1.age);
printf("Height: %.1f\n", person1.height);
return 0;
}

A union allows different data types to share the same memory location. Unlike struct, only one member of a union can hold a value at any given time.

Definition:

union Data {
int intValue;
float floatValue;
char charValue;
};

Key Points:

  • Memory Allocation: The size of a union is the size of its largest member. All members share the same memory space, so updating one member affects the value of the others.

  • Accessing Members: Members are accessed using the dot operator (.) for a union variable.

  • Initialization:

    union Data data;
    data.intValue = 10;

Example Usage:

#include <stdio.h>
union Data {
int intValue;
float floatValue;
char charValue;
};
int main() {
union Data data;
data.intValue = 10;
printf("Integer: %d\n", data.intValue);
data.floatValue = 3.14;
printf("Float: %.2f\n", data.floatValue);
data.charValue = 'A';
printf("Character: %c\n", data.charValue);
return 0;
}

Comparison:

  • Struct:
    • Each member has its own memory location.
    • Can store multiple members at once.
    • Useful for grouping related data together.
  • Union:
    • All members share the same memory location.
    • Only one member can hold a value at a time.
    • Useful for saving memory when only one of the multiple data types needs to be stored at any given time.

Memory Alignment and Padding:

  • Structs may include padding to align members according to their data type’s alignment requirements. This can affect the total size of the struct.
  • Unions do not have padding between members but may include padding to ensure alignment of the largest member.

Use Cases:

  • Structs: Ideal when you need to group data that should be accessed simultaneously (e.g., a record with name, age, and height).
  • Unions: Useful when you need to store one of several possible data types in the same memory location (e.g., a variable that could hold an integer, a float, or a character, but not all at once).