C++学习笔记-宏

宏是C++预处理器的功能,在编译前进行文本替换。宏可以用于条件编译、代码生成和简化重复代码,但需要谨慎使用以避免潜在的问题。

基本宏定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>

// 简单的宏定义
#define PI 3.14159
#define MAX_SIZE 100
#define SQUARE(x) ((x) * (x))

// 条件编译宏
// 项目->属性->预处理器->预处理器定义->Debug->添加预处理器定义MY_DEBUG=1;
#if MY_DEBUG == 1
#define LOG(x) std::cout << x << std::endl  // 注意这里不要写分号,应该在使用宏的地方写分号
#else
#define LOG(x)  // 在Release版本中,LOG宏被定义为空
#endif

int main()
{
    std::cout << "PI = " << PI << std::endl;
    std::cout << "Max size = " << MAX_SIZE << std::endl;
    std::cout << "Square of 5 = " << SQUARE(5) << std::endl;
    
    LOG("Debug message");
    LOG(42);
    LOG("This will only appear in debug builds");
    
    return 0;
}

宏的高级用法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <string>

// 多行宏定义
#define DECLARE_GETTER_SETTER(type, name) \
    private: \
        type m_##name; \
    public: \
        const type& Get##name() const { return m_##name; } \
        void Set##name(const type& value) { m_##name = value; }

// 字符串化操作符 #
#define STRINGIFY(x) #x
#define TO_STRING(x) STRINGIFY(x)

// 连接操作符 ##
#define CONCAT(a, b) a##b

// 可变参数宏
#define PRINT_ARGS(...) printf(__VA_ARGS__)
#define LOG_INFO(format, ...) printf("[INFO] " format "\n", ##__VA_ARGS__)

// 调试宏
#ifdef _DEBUG
    #define ASSERT(condition, message) \
        do { \
            if (!(condition)) { \
                std::cerr << "Assertion failed: " << #condition \
                          << " in " << __FILE__ << " at line " << __LINE__ \
                          << ": " << message << std::endl; \
                std::abort(); \
            } \
        } while(0)
#else
    #define ASSERT(condition, message) ((void)0)
#endif

class Example
{
    DECLARE_GETTER_SETTER(std::string, Name)
    DECLARE_GETTER_SETTER(int, Age)
    
public:
    Example() : m_Name(""), m_Age(0) {}
};

int main()
{
    // 使用生成的getter/setter
    Example obj;
    obj.SetName("Alice");
    obj.SetAge(25);
    
    std::cout << "Name: " << obj.GetName() << std::endl;
    std::cout << "Age: " << obj.GetAge() << std::endl;
    
    // 字符串化
    std::cout << "Stringified: " << STRINGIFY(Hello World) << std::endl;
    std::cout << "To string: " << TO_STRING(123) << std::endl;
    
    // 连接
    int CONCAT(var, 1) = 10;
    int CONCAT(var, 2) = 20;
    std::cout << "var1 = " << var1 << ", var2 = " << var2 << std::endl;
    
    // 可变参数宏
    LOG_INFO("User %s logged in with ID %d", "Alice", 1001);
    LOG_INFO("System started");
    
    // 断言(仅在Debug模式下有效)
    int value = 5;
    ASSERT(value > 0, "Value must be positive");
    // ASSERT(value > 10, "This will fail");  // 取消注释会触发断言
    
    return 0;
}

预定义宏

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>

void ShowPredefinedMacros()
{
    std::cout << "=== Predefined Macros ===" << std::endl;
    std::cout << "File: " << __FILE__ << std::endl;
    std::cout << "Line: " << __LINE__ << std::endl;
    std::cout << "Function: " << __FUNCTION__ << std::endl;
    std::cout << "Date: " << __DATE__ << std::endl;
    std::cout << "Time: " << __TIME__ << std::endl;
    
#ifdef _WIN32
    std::cout << "Platform: Windows" << std::endl;
#elif defined(__linux__)
    std::cout << "Platform: Linux" << std::endl;
#elif defined(__APPLE__)
    std::cout << "Platform: macOS" << std::endl;
#endif

#ifdef _DEBUG
    std::cout << "Build: Debug" << std::endl;
#else
    std::cout << "Build: Release" << std::endl;
#endif

#ifdef _MSC_VER
    std::cout << "Compiler: MSVC " << _MSC_VER << std::endl;
#elif defined(__GNUC__)
    std::cout << "Compiler: GCC " << __GNUC__ << "." << __GNUC_MINOR__ << std::endl;
#elif defined(__clang__)
    std::cout << "Compiler: Clang " << __clang_major__ << "." << __clang_minor__ << std::endl;
#endif

    std::cout << "C++ Standard: " << __cplusplus << std::endl;
}

int main()
{
    ShowPredefinedMacros();
    return 0;
}

条件编译的实际应用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <iostream>

// 平台特定代码
#ifdef _WIN32
    #include <windows.h>
    #define SLEEP(ms) Sleep(ms)
    #define CLEAR_SCREEN() system("cls")
#else
    #include <unistd.h>
    #define SLEEP(ms) usleep((ms) * 1000)
    #define CLEAR_SCREEN() system("clear")
#endif

// 功能开关
#define FEATURE_LOGGING 1
#define FEATURE_PROFILING 0
#define FEATURE_NETWORKING 1

#if FEATURE_LOGGING
    #define LOG_ENABLED
    #define LOG(msg) std::cout << "[LOG] " << msg << std::endl
#else
    #define LOG(msg)
#endif

#if FEATURE_PROFILING
    #include <chrono>
    #define PROFILE_SCOPE(name) ProfileTimer timer(name)
    
    class ProfileTimer
    {
    private:
        std::string m_Name;
        std::chrono::time_point<std::chrono::high_resolution_clock> m_StartTime;
        
    public:
        ProfileTimer(const std::string& name) : m_Name(name)
        {
            m_StartTime = std::chrono::high_resolution_clock::now();
        }
        
        ~ProfileTimer()
        {
            auto endTime = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - m_StartTime);
            std::cout << "[PROFILE] " << m_Name << " took " << duration.count() << " microseconds" << std::endl;
        }
    };
#else
    #define PROFILE_SCOPE(name)
#endif

// 版本控制
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_PATCH 3
#define VERSION_STRING TO_STRING(VERSION_MAJOR) "." TO_STRING(VERSION_MINOR) "." TO_STRING(VERSION_PATCH)

void SomeFunction()
{
    PROFILE_SCOPE("SomeFunction");
    LOG("Executing SomeFunction");
    
    // 模拟一些工作
    for (int i = 0; i < 1000000; ++i)
    {
        volatile int temp = i * i;
    }
    
    LOG("SomeFunction completed");
}

int main()
{
    std::cout << "Application Version: " << VERSION_STRING << std::endl;
    
    LOG("Application started");
    
    SomeFunction();
    
#if FEATURE_NETWORKING
    LOG("Networking feature is enabled");
#else
    LOG("Networking feature is disabled");
#endif
    
    LOG("Application finished");
    
    return 0;
}

宏的陷阱和最佳实践

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream>

// 错误的宏定义示例
#define BAD_MAX(a, b) a > b ? a : b  // 没有括号,可能导致优先级问题
#define BAD_SQUARE(x) x * x          // 没有括号,可能导致意外结果

// 正确的宏定义
#define GOOD_MAX(a, b) ((a) > (b) ? (a) : (b))
#define GOOD_SQUARE(x) ((x) * (x))

// 多次求值问题
#define UNSAFE_MAX(a, b) ((a) > (b) ? (a) : (b))  // 参数可能被多次求值

// 更安全的版本(使用语句表达式,GCC扩展)
#define SAFE_MAX(a, b) ({ \
    __typeof__(a) _a = (a); \
    __typeof__(b) _b = (b); \
    _a > _b ? _a : _b; \
})

// 使用do-while(0)技巧确保宏像语句一样工作
#define SAFE_LOG(msg) \
    do { \
        std::cout << "[LOG] " << msg << std::endl; \
    } while(0)

void DemonstrateMacroProblems()
{
    std::cout << "=== Macro Problems Demo ===" << std::endl;
    
    // 优先级问题
    int result1 = BAD_MAX(1, 2) + 3;    // 展开为: 1 > 2 ? 1 : 2 + 3 = 5 (错误!)
    int result2 = GOOD_MAX(1, 2) + 3;   // 展开为: ((1) > (2) ? (1) : (2)) + 3 = 5 (正确)
    
    std::cout << "BAD_MAX(1, 2) + 3 = " << result1 << std::endl;
    std::cout << "GOOD_MAX(1, 2) + 3 = " << result2 << std::endl;
    
    // 参数问题
    int x = 5;
    int bad_result = BAD_SQUARE(x + 1);   // 展开为: x + 1 * x + 1 = 11 (错误!)
    int good_result = GOOD_SQUARE(x + 1); // 展开为: ((x + 1) * (x + 1)) = 36 (正确)
    
    std::cout << "BAD_SQUARE(5 + 1) = " << bad_result << std::endl;
    std::cout << "GOOD_SQUARE(5 + 1) = " << good_result << std::endl;
    
    // 多次求值问题
    int counter = 0;
    auto increment = [&counter]() { return ++counter; };
    
    std::cout << "Counter before: " << counter << std::endl;
    int unsafe_result = UNSAFE_MAX(increment(), 5);  // increment()可能被调用多次
    std::cout << "Counter after UNSAFE_MAX: " << counter << std::endl;
    
    counter = 0;
    // int safe_result = SAFE_MAX(increment(), 5);  // 仅在支持GCC扩展的编译器中有效
    // std::cout << "Counter after SAFE_MAX: " << counter << std::endl;
}

// 宏与模板的比较
template<typename T>
constexpr T TemplateMax(const T& a, const T& b)
{
    return a > b ? a : b;
}

void MacroVsTemplate()
{
    std::cout << "\n=== Macro vs Template ===" << std::endl;
    
    // 宏版本
    int macro_result = GOOD_MAX(10, 20);
    double macro_result_d = GOOD_MAX(3.14, 2.71);
    
    // 模板版本
    int template_result = TemplateMax(10, 20);
    double template_result_d = TemplateMax(3.14, 2.71);
    
    std::cout << "Macro int result: " << macro_result << std::endl;
    std::cout << "Template int result: " << template_result << std::endl;
    std::cout << "Macro double result: " << macro_result_d << std::endl;
    std::cout << "Template double result: " << template_result_d << std::endl;
}

int main()
{
    DemonstrateMacroProblems();
    MacroVsTemplate();
    
    // 正确使用SAFE_LOG
    if (true)
        SAFE_LOG("This works correctly in if statements");
    
    return 0;
}

实用宏示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <memory>

// 禁用拷贝和赋值的宏
#define DISABLE_COPY(ClassName) \
    ClassName(const ClassName&) = delete; \
    ClassName& operator=(const ClassName&) = delete;

// 禁用移动的宏
#define DISABLE_MOVE(ClassName) \
    ClassName(ClassName&&) = delete; \
    ClassName& operator=(ClassName&&) = delete;

// 禁用拷贝和移动的宏
#define DISABLE_COPY_AND_MOVE(ClassName) \
    DISABLE_COPY(ClassName) \
    DISABLE_MOVE(ClassName)

// 单例模式宏
#define SINGLETON(ClassName) \
    public: \
        static ClassName& GetInstance() { \
            static ClassName instance; \
            return instance; \
        } \
    private: \
        ClassName() = default; \
        DISABLE_COPY_AND_MOVE(ClassName)

// 属性声明宏
#define PROPERTY(type, name) \
    private: \
        type m_##name; \
    public: \
        const type& Get##name() const { return m_##name; } \
        void Set##name(const type& value) { m_##name = value; } \
        type& name() { return m_##name; } \
        const type& name() const { return m_##name; }

class NonCopyable
{
    DISABLE_COPY_AND_MOVE(NonCopyable)
    
public:
    NonCopyable() = default;
    void DoSomething() { std::cout << "NonCopyable doing something" << std::endl; }
};

class Logger
{
    SINGLETON(Logger)
    
public:
    void Log(const std::string& message)
    {
        std::cout << "[SINGLETON LOG] " << message << std::endl;
    }
};

class Person
{
    PROPERTY(std::string, Name)
    PROPERTY(int, Age)
    
public:
    Person() : m_Name(""), m_Age(0) {}
    
    void Print() const
    {
        std::cout << "Person: " << GetName() << ", Age: " << GetAge() << std::endl;
    }
};

int main()
{
    // 使用非拷贝类
    NonCopyable obj;
    obj.DoSomething();
    // NonCopyable obj2 = obj;  // 编译错误:拷贝被禁用
    
    // 使用单例
    Logger::GetInstance().Log("Application started");
    Logger::GetInstance().Log("Some operation completed");
    
    // 使用属性宏
    Person person;
    person.SetName("Alice");
    person.SetAge(30);
    person.Print();
    
    // 直接访问属性
    person.Name() = "Bob";
    person.Age() = 25;
    person.Print();
    
    return 0;
}

总结

  1. 宏的本质:宏是代码生成的一种方式,在预处理阶段进行文本替换
  2. 使用场景
    • 条件编译(Debug/Release、平台特定代码)
    • 代码生成(减少重复代码)
    • 常量定义
    • 调试和日志
  3. 注意事项
    • 使用括号避免优先级问题
    • 注意多次求值问题
    • 使用do-while(0)技巧
    • 优先考虑const、constexpr和模板
  4. 最佳实践
    • 宏名使用大写字母
    • 复杂逻辑优先使用模板而非宏
    • 谨慎使用,避免过度复杂化代码
updatedupdated2025-09-202025-09-20