C Programming: Low-Level Mastery
Preprocessor

Pragma Directives

Master #pragma directives for compiler-specific control: packing structures, optimization hints, warnings, deprecated functions, and platform-specific features. Learn standard and compiler-specific pragmas.

What are Pragmas?

#pragma provides compiler-specific directives. Unlike standard C features, pragmas vary by compiler. Unknown pragmas are ignored, so code remains portable. Use pragmas for optimization, warnings, structure packing, and platform features. Always provide non-pragma alternatives when possible.

C
#include <stdio.h>

/* Basic pragma syntax */
#pragma directive_name

/* Compiler-specific pragmas */

/* GCC/Clang */
#pragma GCC diagnostic ignored "-Wunused-variable"

/* MSVC */
#pragma warning(disable: 4996)

/* Standard pragmas (C99+) */
#pragma STDC FP_CONTRACT ON
#pragma STDC FENV_ACCESS ON
#pragma STDC CX_LIMITED_RANGE ON

/* _Pragma operator (C99) - can be used in macros */
_Pragma("pack(1)")

/* Equivalent to */
#pragma pack(1)

/* Using _Pragma in macros */
#define DISABLE_WARNING(text) _Pragma(#text)

DISABLE_WARNING(GCC diagnostic ignored "-Wunused")

/* Pragma sections */
#pragma section_start
/* Code here */
#pragma section_end

/* Unknown pragmas ignored (portability) */
#pragma some_unknown_feature
/* No error, just ignored */

/* Common pragma uses:
   - Structure packing
   - Warning control
   - Optimization hints
   - Code sections
   - Function attributes
   - Deprecated warnings
   - Platform features
*/

Structure Packing

Compilers add padding between struct members for alignment. #pragma pack controls this. Packed structures save space but may cause slower access or alignment issues. Essential for binary file formats, network protocols, and interfacing with hardware.

C
#include <stdio.h>

/* Normal structure (with padding) */
struct Normal {
    char c;     /* 1 byte */
                /* 3 bytes padding */
    int i;      /* 4 bytes */
    char c2;    /* 1 byte */
                /* 3 bytes padding */
};  /* Total: 12 bytes */

/* Packed structure (no padding) */
#pragma pack(push, 1)
struct Packed {
    char c;     /* 1 byte */
    int i;      /* 4 bytes */
    char c2;    /* 1 byte */
};  /* Total: 6 bytes */
#pragma pack(pop)

void packing_example(void) {
    printf("Normal: %zu bytes\n", sizeof(struct Normal));  /* 12 */
    printf("Packed: %zu bytes\n", sizeof(struct Packed));  /* 6 */
}

/* Different pack values */

/* 1-byte alignment (tightest) */
#pragma pack(1)
struct Pack1 {
    char c;
    int i;
};  /* 5 bytes */
#pragma pack()

/* 2-byte alignment */
#pragma pack(2)
struct Pack2 {
    char c;
    int i;
};  /* 6 bytes */
#pragma pack()

/* 4-byte alignment (default on many systems) */
#pragma pack(4)
struct Pack4 {
    char c;
    int i;
};  /* 8 bytes */
#pragma pack()

/* Push/pop pattern (save/restore) */
#pragma pack(push)  /* Save current */
#pragma pack(1)     /* Set to 1 */

struct MyStruct {
    /* ... */
};

#pragma pack(pop)   /* Restore previous */

/* Named push/pop */
#pragma pack(push, tight_pack)
#pragma pack(1)
/* ... structures ... */
#pragma pack(pop, tight_pack)

/* Platform-specific packing */

/* GCC/Clang attribute */
struct __attribute__((packed)) PackedGCC {
    char c;
    int i;
};  /* 5 bytes */

/* MSVC */
#pragma pack(push, 1)
struct PackedMSVC {
    char c;
    int i;
};
#pragma pack(pop)

/* Portable packed structure */
#if defined(__GNUC__)
    #define PACKED __attribute__((packed))
#elif defined(_MSC_VER)
    #define PACKED
    #pragma pack(push, 1)
#else
    #define PACKED
#endif

struct PACKED PortableStruct {
    char c;
    int i;
};

#ifdef _MSC_VER
    #pragma pack(pop)
#endif

/* Binary file format example */
#pragma pack(push, 1)
struct FileHeader {
    uint32_t magic;      /* Magic number */
    uint16_t version;    /* File version */
    uint32_t size;       /* Data size */
    uint16_t flags;      /* Flags */
};
#pragma pack(pop)

/* Networking protocol */
#pragma pack(push, 1)
struct PacketHeader {
    uint8_t type;
    uint16_t length;
    uint32_t sequence;
    uint8_t checksum;
};
#pragma pack(pop)

/* Performance considerations */
void alignment_performance(void) {
    /* Aligned access (fast) */
    struct Aligned {
        int x;
    } __attribute__((aligned(4)));
    
    /* Packed access (slower on some architectures) */
    #pragma pack(push, 1)
    struct PackedSlow {
        char padding;
        int x;  /* Misaligned! */
    };
    #pragma pack(pop)
}

/* When to use packing */
/*
   Use #pragma pack when:
   - Reading/writing binary files
   - Network protocols
   - Hardware registers
   - Interfacing with other languages
   
   Don't use when:
   - Performance critical
   - Only internal structures
   - Not required by spec
*/

Warning Control

Pragmas control compiler warnings: disable specific warnings, treat warnings as errors, push/pop warning state. Use carefully - suppressed warnings may hide bugs. Document why warnings are disabled. Prefer fixing code over suppressing warnings.

C
/* GCC/Clang warning control */

/* Disable specific warning */
#pragma GCC diagnostic ignored "-Wunused-variable"

int unused_var;  /* No warning */

/* Push/pop warning state */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"

void function(int unused) {  /* No warning */
    /* ... */
}

#pragma GCC diagnostic pop

/* Now warnings restored */

/* Multiple warnings */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wformat"

/* Code with suppressed warnings */

#pragma GCC diagnostic pop

/* Treat warning as error */
#pragma GCC diagnostic error "-Wformat"

/* Invalid format causes compile error */
// printf("%d", "string");  /* Error! */

/* MSVC warning control */

/* Disable warning */
#pragma warning(disable: 4996)  /* Deprecated function */

/* Enable warning */
#pragma warning(default: 4996)

/* Treat as error */
#pragma warning(error: 4996)

/* Push/pop */
#pragma warning(push)
#pragma warning(disable: 4996)
/* Code */
#pragma warning(pop)

/* Multiple warnings */
#pragma warning(disable: 4244 4267 4305)

/* Portable warning suppression */
#if defined(__GNUC__)
    #define SUPPRESS_WARNING_PUSH \
        _Pragma("GCC diagnostic push")
    #define SUPPRESS_WARNING(w) \
        _Pragma(#w)
    #define SUPPRESS_WARNING_POP \
        _Pragma("GCC diagnostic pop")
#elif defined(_MSC_VER)
    #define SUPPRESS_WARNING_PUSH \
        __pragma(warning(push))
    #define SUPPRESS_WARNING(w) \
        __pragma(warning(disable: w))
    #define SUPPRESS_WARNING_POP \
        __pragma(warning(pop))
#else
    #define SUPPRESS_WARNING_PUSH
    #define SUPPRESS_WARNING(w)
    #define SUPPRESS_WARNING_POP
#endif

/* Usage */
SUPPRESS_WARNING_PUSH
SUPPRESS_WARNING(-Wunused-variable)

int unused;

SUPPRESS_WARNING_POP

/* Common warnings to control */

/* Unused variable */
#pragma GCC diagnostic ignored "-Wunused-variable"

/* Unused parameter */
#pragma GCC diagnostic ignored "-Wunused-parameter"

/* Format string */
#pragma GCC diagnostic ignored "-Wformat"

/* Sign comparison */
#pragma GCC diagnostic ignored "-Wsign-compare"

/* Type limits */
#pragma GCC diagnostic ignored "-Wtype-limits"

/* Deprecated */
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

/* Example: Suppressing in specific code */
void legacy_api(int param) {
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    
    old_function();  /* Deprecated but needed */
    
    #pragma GCC diagnostic pop
}

/* Document why warnings suppressed */
/* Suppress false positive from static analyzer */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"

int value;  /* Actually initialized below */
if (condition) {
    value = 10;
} else {
    value = 20;
}

#pragma GCC diagnostic pop

/* Better: Fix code instead */
int value = condition ? 10 : 20;  /* No warning */

Optimization and Function Attributes

Pragmas provide optimization hints: inline expansion, loop unrolling, function attributes. Help compiler generate better code. Non-portable but powerful for performance-critical sections.

C
/* GCC function attributes via pragma */

/* Optimize function */
#pragma GCC optimize("O3")
void fast_function(void) {
    /* Compiled with O3 regardless of global setting */
}

/* Disable optimization */
#pragma GCC optimize("O0")
void debug_function(void) {
    /* Not optimized - easier debugging */
}

/* Target-specific optimization */
#pragma GCC target("avx2")
void simd_function(void) {
    /* Can use AVX2 instructions */
}

/* MSVC optimization */
#pragma optimize("", off)
void no_optimize(void) {
    /* Optimization off */
}
#pragma optimize("", on)

/* Inlining hints */
#pragma GCC push_options
#pragma GCC optimize("inline-functions")

void inline_candidate(void) {
    /* More likely to be inlined */
}

#pragma GCC pop_options

/* Loop unrolling */
void loop_function(void) {
    #pragma GCC unroll 4
    for (int i = 0; i < 16; i++) {
        /* Loop unrolled 4x */
    }
    
    #pragma GCC unroll 8
    for (int i = 0; i < 64; i++) {
        /* Loop unrolled 8x */
    }
}

/* Vectorization hints */
void vector_function(void) {
    int a[1000], b[1000], c[1000];
    
    #pragma GCC ivdep  /* Ignore dependencies */
    for (int i = 0; i < 1000; i++) {
        a[i] = b[i] + c[i];
    }
}

/* OpenMP pragmas (if supported) */
void parallel_function(void) {
    #pragma omp parallel for
    for (int i = 0; i < 1000; i++) {
        /* Parallelized loop */
    }
}

/* MSVC code sections */
#pragma code_seg(".text")
void normal_function(void) {
    /* In .text section */
}

#pragma code_seg(".hotpath")
void hot_function(void) {
    /* In custom section */
}
#pragma code_seg()

/* Function alignment */
#pragma GCC push_options
#pragma GCC optimize("align-functions=32")

void aligned_function(void) {
    /* 32-byte aligned for cache */
}

#pragma GCC pop_options

/* Compiler barriers */
void barrier_example(void) {
    int x = 0;
    
    #pragma GCC memory_order_seq_cst
    x = 1;  /* Memory fence */
}

/* CPU detection */
#ifdef __AVX2__
    #pragma GCC target("avx2")
    void avx2_optimized(void) {
        /* AVX2 code */
    }
#else
    void avx2_optimized(void) {
        /* Fallback */
    }
#endif

/* Profile-guided optimization */
#pragma GCC pgo("hot")
void frequently_called(void) {
    /* Marked as hot path */
}

#pragma GCC pgo("cold")
void rarely_called(void) {
    /* Marked as cold path */
}

Deprecation and Compatibility

Mark functions, types, or macros as deprecated. Warns users to migrate to newer APIs. Provides transition period. Essential for library maintenance and API evolution.

C
/* GCC deprecation */
__attribute__((deprecated))
void old_function(void);

__attribute__((deprecated("Use new_function instead")))
void old_function2(void);

/* MSVC deprecation */
__declspec(deprecated)
void old_function3(void);

__declspec(deprecated("Use new_function instead"))
void old_function4(void);

/* Portable deprecation macro */
#if defined(__GNUC__)
    #define DEPRECATED(msg) __attribute__((deprecated(msg)))
#elif defined(_MSC_VER)
    #define DEPRECATED(msg) __declspec(deprecated(msg))
#else
    #define DEPRECATED(msg)
#endif

DEPRECATED("Use new_api instead")
void legacy_api(void);

/* Using deprecated functions triggers warnings */
void caller(void) {
    legacy_api();  /* Warning: deprecated */
}

/* Deprecating types */
typedef struct DEPRECATED("Use NewStruct") OldStruct {
    int data;
} OldStruct;

/* Deprecating macros */
#define OLD_MACRO 1  DEPRECATED("Use NEW_MACRO")
#define NEW_MACRO 2

/* Conditional deprecation */
#if API_VERSION >= 2
    DEPRECATED("Removed in version 3")
    void transitional_function(void);
#endif

/* Suppress deprecation warnings */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

void using_deprecated(void) {
    legacy_api();  /* No warning */
}

#pragma GCC diagnostic pop

/* Version-based deprecation */
#if defined(__GNUC__) && (__GNUC__ >= 5)
    #define DEPRECATED_SINCE(ver, msg) \
        __attribute__((deprecated(msg " (deprecated since " #ver ")")))
#else
    #define DEPRECATED_SINCE(ver, msg)
#endif

DEPRECATED_SINCE(2.0, "Use new_function")
void old_function_v2(void);

/* Gradual migration */
/* Version 1.0 */
void api_function(void);  /* Current */

/* Version 2.0 */
DEPRECATED("Use api_function_v2")
void api_function(void);  /* Deprecated */

void api_function_v2(void);  /* New */

/* Version 3.0 */
/* api_function removed */
void api_function_v2(void);  /* Current */

/* Compatibility layers */
#ifndef NO_DEPRECATED_API
    /* Old API still available */
    DEPRECATED("Use new API")
    void old_api(void);
#endif

/* Migration helpers */
#define USE_OLD_API 0

#if USE_OLD_API
    #define API_CALL old_function
#else
    #define API_CALL new_function
#endif

void code(void) {
    API_CALL();  /* Flexible */
}

Platform-Specific Pragmas

Each compiler/platform has unique pragmas. Understanding platform-specific pragmas helps with optimization, debugging, and system integration. Always provide fallbacks for portability.

C
/* GCC/Clang specific */

/* Visibility control */
#pragma GCC visibility push(hidden)
void internal_function(void);  /* Hidden */
#pragma GCC visibility pop

/* Weak symbols */
__attribute__((weak))
void overridable_function(void) {
    /* Default implementation */
}

/* Poison identifiers */
#pragma GCC poison malloc  /* Error if malloc used */

/* System header */
#pragma GCC system_header  /* Treat as system header */

/* MSVC specific */

/* Instruction set */
#pragma intrinsic(_ReadBarrier)
#pragma intrinsic(_WriteBarrier)

/* DLL export/import */
#pragma comment(lib, "user32.lib")

/* Data sections */
#pragma data_seg(".mydata")
int shared_data = 0;
#pragma data_seg()

/* Init sections */
#pragma init_seg(compiler)
#pragma init_seg(lib)
#pragma init_seg(user)

/* Intel compiler */

/* Vectorization */
#pragma ivdep
#pragma vector always
#pragma simd

/* HP-UX */
#pragma HP_INLINE

/* IBM XL */
#pragma isolated_call

/* Portable wrapper example */
#if defined(__GNUC__)
    #define WEAK __attribute__((weak))
    #define EXPORT __attribute__((visibility("default")))
#elif defined(_MSC_VER)
    #define WEAK
    #define EXPORT __declspec(dllexport)
#else
    #define WEAK
    #define EXPORT
#endif

WEAK void plugin_init(void) {
    /* Can be overridden */
}

EXPORT void public_api(void) {
    /* Exported */
}

/* Conditional pragma usage */
#if defined(__GNUC__) && !defined(__clang__)
    /* GCC-only pragma */
    #pragma GCC optimize("tree-vectorize")
#endif

#ifdef _MSC_VER
    /* MSVC-only */
    #pragma warning(disable: 4100)
#endif

/* Feature detection */
#ifdef __has_attribute
    #if __has_attribute(warn_unused_result)
        #define MUST_USE __attribute__((warn_unused_result))
    #else
        #define MUST_USE
    #endif
#else
    #define MUST_USE
#endif

MUST_USE int important_function(void);

/* Pragma in macros */
#define OPTIMIZE_FUNC \
    _Pragma("GCC optimize(\"O3\")")

OPTIMIZE_FUNC
void fast_func(void) {
    /* ... */
}

Summary & What's Next

Key Takeaways:

  • ✅ #pragma provides compiler-specific directives
  • ✅ Unknown pragmas are ignored (portability)
  • ✅ #pragma pack controls structure alignment
  • ✅ Warning control with push/pop
  • ✅ Optimization hints for performance
  • ✅ Deprecation warnings for API migration
  • ✅ Platform-specific features available
  • ✅ Always provide portable fallbacks

What's Next?

Let's learn about advanced C topics like variadic functions and inline assembly!