c
exercises
exercises.c🔧c
/**
* =============================================================================
* Conditional Compilation in C - Exercises
* =============================================================================
*
* Practice exercises for conditional compilation techniques.
* Complete each exercise by adding the appropriate preprocessor directives.
*
* Compile with different flags to test:
* gcc -Wall -Wextra -std=c99 -o exercises exercises.c
* gcc -DDEBUG -o exercises_debug exercises.c
* gcc -DPLATFORM_LINUX -o exercises_linux exercises.c
*
* =============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// =============================================================================
// Exercise 1: Basic Conditional Compilation
// =============================================================================
/**
* Define the following using #ifdef, #ifndef, and #define:
*
* 1. If DEBUG is defined, define DEBUG_MODE as 1, otherwise as 0
* 2. If MAX_USERS is not defined, set a default of 100
* 3. If TIMEOUT is not defined, set a default of 30
* 4. Create a DEBUG_PRINT macro that only prints when DEBUG is defined
*/
// YOUR CODE HERE
void exercise1(void) {
printf("=== Exercise 1: Basic Conditional Compilation ===\n");
// These should work after implementing the macros
// printf("DEBUG_MODE: %d\n", DEBUG_MODE);
// printf("MAX_USERS: %d\n", MAX_USERS);
// printf("TIMEOUT: %d\n", TIMEOUT);
// This should only print in debug mode
// DEBUG_PRINT("This is a debug message");
printf("\n");
}
// =============================================================================
// Exercise 2: Multi-level Log System
// =============================================================================
/**
* Create a configurable logging system using conditional compilation:
*
* 1. Define LOG_LEVEL (if not already defined) with a default of 2
* 2. Create these logging macros based on LOG_LEVEL:
* - LOG_ERROR (level >= 1)
* - LOG_WARN (level >= 2)
* - LOG_INFO (level >= 3)
* - LOG_DEBUG (level >= 4)
* 3. Each macro should print: [LEVEL] message
* 4. If LOG_LEVEL is 0, all logging should be disabled
*/
// YOUR CODE HERE
void exercise2(void) {
printf("=== Exercise 2: Multi-level Log System ===\n");
// Uncomment after implementing
// printf("Current LOG_LEVEL: %d\n\n", LOG_LEVEL);
// LOG_ERROR("This is an error message");
// LOG_WARN("This is a warning message");
// LOG_INFO("This is an info message");
// LOG_DEBUG("This is a debug message");
printf("\n");
}
// =============================================================================
// Exercise 3: Platform Detection
// =============================================================================
/**
* Create platform detection macros:
*
* 1. Detect if running on Windows, Linux, or macOS
* 2. Define PLATFORM_NAME as a string ("Windows", "Linux", "macOS", "Unknown")
* 3. Define PATH_SEP as the path separator ('\\' for Windows, '/' for others)
* 4. Define a NEWLINE macro ("\r\n" for Windows, "\n" for others)
* 5. Create a platform_init() function with platform-specific code
*/
// YOUR CODE HERE
void exercise3(void) {
printf("=== Exercise 3: Platform Detection ===\n");
// Uncomment after implementing
// printf("Platform: %s\n", PLATFORM_NAME);
// printf("Path separator: '%c'\n", PATH_SEP);
// printf("Newline: %s (escaped)\n", "...");
// platform_init();
printf("\n");
}
// =============================================================================
// Exercise 4: Feature Toggles
// =============================================================================
/**
* Implement a feature toggle system:
*
* 1. Define feature flags: FEATURE_A (1), FEATURE_B (0), FEATURE_C (1)
* 2. Create FEATURE_ENABLED(x) macro to check if a feature is enabled
* 3. Conditionally include code only when specific features are enabled
* 4. Create a function that prints which features are active
*/
// YOUR CODE HERE
void exercise4(void) {
printf("=== Exercise 4: Feature Toggles ===\n");
// Uncomment after implementing
// printf("Feature A: %s\n", FEATURE_ENABLED(FEATURE_A) ? "Enabled" : "Disabled");
// printf("Feature B: %s\n", FEATURE_ENABLED(FEATURE_B) ? "Enabled" : "Disabled");
// printf("Feature C: %s\n", FEATURE_ENABLED(FEATURE_C) ? "Enabled" : "Disabled");
// print_active_features();
printf("\n");
}
// =============================================================================
// Exercise 5: Version-Based Compilation
// =============================================================================
/**
* Create version-based feature availability:
*
* 1. Define APP_VERSION as a number (e.g., 200 for version 2.0.0)
* 2. Based on version:
* - Version < 100: Define LEGACY_MODE
* - Version >= 100: Define MODERN_MODE
* - Version >= 200: Also define ADVANCED_FEATURES
* - Version >= 300: Also define EXPERIMENTAL_FEATURES
* 3. Create functions that exist only in certain versions
*/
// YOUR CODE HERE
void exercise5(void) {
printf("=== Exercise 5: Version-Based Compilation ===\n");
// Uncomment after implementing
// printf("App Version: %d\n", APP_VERSION);
// #ifdef LEGACY_MODE
// printf("Running in legacy mode\n");
// #endif
// #ifdef MODERN_MODE
// printf("Running in modern mode\n");
// #endif
// #ifdef ADVANCED_FEATURES
// printf("Advanced features available\n");
// #endif
// #ifdef EXPERIMENTAL_FEATURES
// printf("Experimental features available\n");
// #endif
printf("\n");
}
// =============================================================================
// Exercise 6: Compiler Detection
// =============================================================================
/**
* Create compiler detection macros:
*
* 1. Detect GCC, Clang, or MSVC
* 2. Define COMPILER_NAME string
* 3. Define compiler-specific warning disable macros
* 4. Create portable UNUSED macro for unused parameters
* 5. Create portable DEPRECATED macro for deprecated functions
*/
// YOUR CODE HERE
void exercise6(void) {
printf("=== Exercise 6: Compiler Detection ===\n");
// Uncomment after implementing
// printf("Compiler: %s\n", COMPILER_NAME);
// Example usage:
// void deprecated_function(void) DEPRECATED;
// void func_with_unused(int used, int UNUSED unused);
printf("\n");
}
// =============================================================================
// Exercise 7: Assert System
// =============================================================================
/**
* Create a custom assertion system:
*
* 1. ASSERT(condition) - basic assertion
* 2. ASSERT_MSG(condition, msg) - assertion with message
* 3. STATIC_ASSERT(condition, msg) - compile-time assertion
* 4. In DEBUG mode: assertions print error and abort
* 5. In RELEASE mode: assertions are disabled (no code generated)
*/
// YOUR CODE HERE
void exercise7(void) {
printf("=== Exercise 7: Assert System ===\n");
// Uncomment after implementing
// int x = 10;
// ASSERT(x > 0); // Should pass
// ASSERT_MSG(x < 100, "x is too large"); // Should pass
// This would fail in debug mode:
// ASSERT(x > 100);
// Static assert (compile-time):
// STATIC_ASSERT(sizeof(int) >= 4, "int must be at least 4 bytes");
printf("\n");
}
// =============================================================================
// Exercise 8: Build Mode Configuration
// =============================================================================
/**
* Create build mode configurations:
*
* 1. Define three build modes: DEBUG, TEST, RELEASE
* 2. Only one mode should be active at a time
* 3. Each mode should configure:
* - OPTIMIZATION_LEVEL (0, 1, or 2)
* - LOGGING_ENABLED (1 or 0)
* - ASSERTIONS_ENABLED (1 or 0)
* - BUILD_MODE_NAME (string)
* 4. Use #error if no mode or multiple modes are defined
*/
// YOUR CODE HERE
// Note: Comment out the #error checks for the exercise to compile
void exercise8(void) {
printf("=== Exercise 8: Build Mode Configuration ===\n");
// Uncomment after implementing
// printf("Build Mode: %s\n", BUILD_MODE_NAME);
// printf("Optimization Level: %d\n", OPTIMIZATION_LEVEL);
// printf("Logging: %s\n", LOGGING_ENABLED ? "Enabled" : "Disabled");
// printf("Assertions: %s\n", ASSERTIONS_ENABLED ? "Enabled" : "Disabled");
printf("\n");
}
// =============================================================================
// Exercise 9: Conditional Function Implementation
// =============================================================================
/**
* Create functions with conditional implementations:
*
* 1. Define USE_FAST_MATH or USE_PRECISE_MATH
* 2. Implement calculate_sqrt() differently based on the flag
* 3. Implement sort_array() using quicksort or bubblesort based on a flag
* 4. Use #warning to indicate which implementation is being used
*/
// YOUR CODE HERE
void exercise9(void) {
printf("=== Exercise 9: Conditional Function Implementation ===\n");
// Uncomment after implementing
// double result = calculate_sqrt(16.0);
// printf("sqrt(16) = %.4f\n", result);
// int arr[] = {5, 2, 8, 1, 9};
// sort_array(arr, 5);
// printf("Sorted: ");
// for (int i = 0; i < 5; i++) printf("%d ", arr[i]);
// printf("\n");
printf("\n");
}
// =============================================================================
// Exercise 10: Complete Configuration System
// =============================================================================
/**
* Create a complete configuration system:
*
* 1. Define configuration macros for:
* - Memory limits (STACK_SIZE, HEAP_SIZE)
* - Threading (MAX_THREADS, THREAD_STACK_SIZE)
* - Network (MAX_CONNECTIONS, BUFFER_SIZE)
* - Features (ENABLE_SSL, ENABLE_COMPRESSION)
*
* 2. Provide defaults for all values
* 3. Validate configuration with #error for invalid combinations
* 4. Create a print_configuration() function
*/
// YOUR CODE HERE
void exercise10(void) {
printf("=== Exercise 10: Complete Configuration System ===\n");
// Uncomment after implementing
// print_configuration();
printf("\n");
}
// =============================================================================
// Main Function
// =============================================================================
int main(void) {
printf("============================================================\n");
printf(" CONDITIONAL COMPILATION - EXERCISES \n");
printf("============================================================\n\n");
exercise1();
exercise2();
exercise3();
exercise4();
exercise5();
exercise6();
exercise7();
exercise8();
exercise9();
exercise10();
printf("============================================================\n");
printf("Complete the exercises by implementing the preprocessor\n");
printf("directives. Test with different compiler flags!\n");
printf("============================================================\n");
return 0;
}
// =============================================================================
// ANSWER KEY
// =============================================================================
/*
* Below are the solutions. Try to solve the exercises yourself first!
*/
/*
// Exercise 1: Basic Conditional Compilation
#ifdef DEBUG
#define DEBUG_MODE 1
#define DEBUG_PRINT(msg) printf("[DEBUG] %s\n", msg)
#else
#define DEBUG_MODE 0
#define DEBUG_PRINT(msg) ((void)0)
#endif
#ifndef MAX_USERS
#define MAX_USERS 100
#endif
#ifndef TIMEOUT
#define TIMEOUT 30
#endif
// Exercise 2: Multi-level Log System
#ifndef LOG_LEVEL
#define LOG_LEVEL 2
#endif
#if LOG_LEVEL >= 1
#define LOG_ERROR(msg) printf("[ERROR] %s\n", msg)
#else
#define LOG_ERROR(msg) ((void)0)
#endif
#if LOG_LEVEL >= 2
#define LOG_WARN(msg) printf("[WARN] %s\n", msg)
#else
#define LOG_WARN(msg) ((void)0)
#endif
#if LOG_LEVEL >= 3
#define LOG_INFO(msg) printf("[INFO] %s\n", msg)
#else
#define LOG_INFO(msg) ((void)0)
#endif
#if LOG_LEVEL >= 4
#define LOG_DEBUG(msg) printf("[DEBUG] %s\n", msg)
#else
#define LOG_DEBUG(msg) ((void)0)
#endif
// Exercise 3: Platform Detection
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM_NAME "Windows"
#define PATH_SEP '\\'
#define NEWLINE "\r\n"
#elif defined(__linux__)
#define PLATFORM_NAME "Linux"
#define PATH_SEP '/'
#define NEWLINE "\n"
#elif defined(__APPLE__)
#define PLATFORM_NAME "macOS"
#define PATH_SEP '/'
#define NEWLINE "\n"
#else
#define PLATFORM_NAME "Unknown"
#define PATH_SEP '/'
#define NEWLINE "\n"
#endif
void platform_init(void) {
#if defined(_WIN32)
printf("Initializing Windows subsystems...\n");
#elif defined(__linux__)
printf("Initializing Linux subsystems...\n");
#elif defined(__APPLE__)
printf("Initializing macOS subsystems...\n");
#else
printf("Initializing generic subsystems...\n");
#endif
}
// Exercise 4: Feature Toggles
#ifndef FEATURE_A
#define FEATURE_A 1
#endif
#ifndef FEATURE_B
#define FEATURE_B 0
#endif
#ifndef FEATURE_C
#define FEATURE_C 1
#endif
#define FEATURE_ENABLED(x) ((x) != 0)
void print_active_features(void) {
printf("Active features: ");
#if FEATURE_A
printf("A ");
#endif
#if FEATURE_B
printf("B ");
#endif
#if FEATURE_C
printf("C ");
#endif
printf("\n");
}
// Exercise 5: Version-Based Compilation
#ifndef APP_VERSION
#define APP_VERSION 200
#endif
#if APP_VERSION < 100
#define LEGACY_MODE 1
#else
#define MODERN_MODE 1
#endif
#if APP_VERSION >= 200
#define ADVANCED_FEATURES 1
#endif
#if APP_VERSION >= 300
#define EXPERIMENTAL_FEATURES 1
#endif
// Exercise 6: Compiler Detection
#if defined(__GNUC__) && !defined(__clang__)
#define COMPILER_NAME "GCC"
#define UNUSED __attribute__((unused))
#define DEPRECATED __attribute__((deprecated))
#elif defined(__clang__)
#define COMPILER_NAME "Clang"
#define UNUSED __attribute__((unused))
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define COMPILER_NAME "MSVC"
#define UNUSED
#define DEPRECATED __declspec(deprecated)
#else
#define COMPILER_NAME "Unknown"
#define UNUSED
#define DEPRECATED
#endif
// Exercise 7: Assert System
#ifdef DEBUG
#define ASSERT(cond) do { \
if (!(cond)) { \
fprintf(stderr, "Assertion failed: %s\n", #cond); \
fprintf(stderr, "File: %s, Line: %d\n", __FILE__, __LINE__); \
abort(); \
} \
} while(0)
#define ASSERT_MSG(cond, msg) do { \
if (!(cond)) { \
fprintf(stderr, "Assertion failed: %s\n", msg); \
fprintf(stderr, "Condition: %s\n", #cond); \
fprintf(stderr, "File: %s, Line: %d\n", __FILE__, __LINE__); \
abort(); \
} \
} while(0)
#else
#define ASSERT(cond) ((void)0)
#define ASSERT_MSG(cond, msg) ((void)0)
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#else
#define STATIC_ASSERT(cond, msg) \
typedef char static_assert_##__LINE__[(cond) ? 1 : -1]
#endif
// Exercise 8: Build Mode Configuration
// (Define exactly one: BUILD_DEBUG, BUILD_TEST, or BUILD_RELEASE)
#if defined(BUILD_DEBUG)
#define BUILD_MODE_NAME "Debug"
#define OPTIMIZATION_LEVEL 0
#define LOGGING_ENABLED 1
#define ASSERTIONS_ENABLED 1
#elif defined(BUILD_TEST)
#define BUILD_MODE_NAME "Test"
#define OPTIMIZATION_LEVEL 1
#define LOGGING_ENABLED 1
#define ASSERTIONS_ENABLED 1
#elif defined(BUILD_RELEASE)
#define BUILD_MODE_NAME "Release"
#define OPTIMIZATION_LEVEL 2
#define LOGGING_ENABLED 0
#define ASSERTIONS_ENABLED 0
#else
// Default to debug
#define BUILD_MODE_NAME "Debug (default)"
#define OPTIMIZATION_LEVEL 0
#define LOGGING_ENABLED 1
#define ASSERTIONS_ENABLED 1
#endif
// Exercise 9: Conditional Function Implementation
#ifndef USE_PRECISE_MATH
#define USE_FAST_MATH 1
#endif
#include <math.h>
#ifdef USE_FAST_MATH
// Fast approximation
double calculate_sqrt(double x) {
// Newton-Raphson approximation (fewer iterations)
double guess = x / 2.0;
for (int i = 0; i < 5; i++) {
guess = (guess + x / guess) / 2.0;
}
return guess;
}
#else
// Precise calculation
double calculate_sqrt(double x) {
return sqrt(x);
}
#endif
#ifdef USE_QUICKSORT
void sort_array(int arr[], int n) {
// Quicksort implementation
// (simplified for exercise)
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
#else
void sort_array(int arr[], int n) {
// Bubblesort (default)
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
#endif
// Exercise 10: Complete Configuration System
// Memory limits
#ifndef STACK_SIZE
#define STACK_SIZE (1024 * 1024) // 1 MB
#endif
#ifndef HEAP_SIZE
#define HEAP_SIZE (64 * 1024 * 1024) // 64 MB
#endif
// Threading
#ifndef MAX_THREADS
#define MAX_THREADS 16
#endif
#ifndef THREAD_STACK_SIZE
#define THREAD_STACK_SIZE (256 * 1024) // 256 KB
#endif
// Network
#ifndef MAX_CONNECTIONS
#define MAX_CONNECTIONS 1000
#endif
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 4096
#endif
// Features
#ifndef ENABLE_SSL
#define ENABLE_SSL 1
#endif
#ifndef ENABLE_COMPRESSION
#define ENABLE_COMPRESSION 1
#endif
// Validation
#if MAX_THREADS < 1
#error "MAX_THREADS must be at least 1"
#endif
#if BUFFER_SIZE < 256
#error "BUFFER_SIZE must be at least 256"
#endif
void print_configuration(void) {
printf("Configuration:\n");
printf(" Memory:\n");
printf(" Stack Size: %d bytes\n", STACK_SIZE);
printf(" Heap Size: %d bytes\n", HEAP_SIZE);
printf(" Threading:\n");
printf(" Max Threads: %d\n", MAX_THREADS);
printf(" Thread Stack: %d bytes\n", THREAD_STACK_SIZE);
printf(" Network:\n");
printf(" Max Connections: %d\n", MAX_CONNECTIONS);
printf(" Buffer Size: %d bytes\n", BUFFER_SIZE);
printf(" Features:\n");
printf(" SSL: %s\n", ENABLE_SSL ? "Enabled" : "Disabled");
printf(" Compression: %s\n", ENABLE_COMPRESSION ? "Enabled" : "Disabled");
}
*/