当前位置: 首页 > wzjs >正文

烟台建设联合会网站南宁百度快速优化

烟台建设联合会网站,南宁百度快速优化,潍坊那个公司做网站比较好,wordpress错误代码403C —— 宏 基本宏定义符号常量函数式宏 宏的特殊用法多行宏字符串化操作符连接操作符可变参数宏基本语法省略可变参数(C99 和 GNU C 扩展)计算可变参数的个数(GNU C 扩展)**_Generic 可变参数宏(C11) 可变…

C —— 宏

  • 基本宏定义
    • 符号常量
    • 函数式宏
  • 宏的特殊用法
    • 多行宏
    • 字符串化操作符
    • 连接操作符
    • 可变参数宏
      • 基本语法
      • 省略可变参数(C99 和 GNU C 扩展)
      • 计算可变参数的个数(GNU C 扩展)**
      • `_Generic` + 可变参数宏(C11)
    • 可变参数宏的常见用途
    • 注意事项
    • 总结
  • 常用预定义宏
      • 1. `__LINE__` - 当前行号
      • 2. `__FILE__` - 当前文件名
      • 3. `__DATE__` - 编译日期(格式 "MMM DD YYYY")
      • 4. `__TIME__` - 编译时间(格式 "HH:MM:SS")
      • 5. `__STDC__` - 是否遵循 ANSI C 标准
      • 6. `__func__` - 当前函数名(C99)
      • 综合示例:调试日志宏
      • 关键点总结
  • 条件编译
  • C语言条件编译详解
    • 基本条件编译指令
      • 1. `#ifdef` / `#ifndef` / `#endif`
      • 2. `#if` / `#elif` / `#else` / `#endif`
    • 常见应用场景
      • 1. 跨平台开发
      • 2. 调试代码
      • 3. 功能开关
    • 预定义宏与条件编译
    • 实用技巧
      • 1. 宏定义检查
      • 2. 防止头文件重复包含
      • 3. 编译器特定指令
    • 注意事项
    • 高级用法
      • 1. 宏参数的条件编译
      • 2. 静态断言(C11之前)

我们在学习C语言时,很早就接触过了宏的概念,今天我们就对宏这一用法进行详细的梳理:

基本宏定义

符号常量

这种用法我们最熟悉,就是简单定义,然后放到代码段中去用:
在这里插入图片描述

#define PI 3.14159
#define MAX_SIZE 100
#define AUTHOR "John Doe"

这里我们就简单介绍一下,不做过多展开。

函数式宏

除了我们自己可以写函数之外,宏也可以定义函数:
在这里插入图片描述
在这里插入图片描述
这里给所有参数都带上括号,是为了保证运算顺序的正确性。如果不带括号,运算结果可能就会大相径庭:

#define FUCNTION(a,b)(a * b)int main()
{printf("%d\n", FUCNTION(10 + 10,20 + 20));
}

在这里插入图片描述
但是如果我加上括号:

#define FUCNTION(a,b)((a) * (b))int main()
{printf("%d\n", FUCNTION(10 + 10,20 + 20));
}

在这里插入图片描述
因为,宏不对本身做任何处理,它只会傻瓜式的展开,我们来看看两个函数展开之后长啥样子:
在这里插入图片描述
所以在编写宏时,如果运算顺序很重要,记得打上括号哦~。

宏的特殊用法

多行宏

使用反斜杠\可以定义多行宏:

# define SWAP(a,b,type){ \type temp = a; \a = b; \b = temp; \
}int main()
{int x = 10;int y = 20;printf("%d %d\n", x, y);SWAP(x, y, int)printf("%d %d\n", x, y);
}

在这里插入图片描述

字符串化操作符

将宏参数转换为字符串:

#define STR(x) #xint main()
{printf("%s\n", STR(123456));
}

在这里插入图片描述

连接操作符

将两个标记连接成一个:

#define CONCAT(a,b) a##bint main()
{int xy = 10;printf("%d\n", CONCAT(x, y));
}

在这里插入图片描述

可变参数宏

接下来就是一些比较高级的用法了,在 C 语言中,可变参数宏(Variadic Macros)允许宏接受 可变数量的参数,类似于 printf() 这样的可变参数函数。它使用 … 和 VA_ARGS 来实现,是 C99 标准引入的特性。

基本语法

#define MACRO_NAME(fixed_args, ...) replacement_text __VA_ARGS__
... 表示可变参数部分。__VA_ARGS__ 在宏展开时会被替换为传入的可变参数。
#define LOG(fmt,...) printf(fmt,__VA_ARGS__)int main()
{LOG("Hello, %s! Your score is %d.\n", "Alice", 95);
}

省略可变参数(C99 和 GNU C 扩展)

如果可变参数可能为空,C99 要求至少有一个参数,但 GNU C 允许完全省略:

// C99 标准写法(必须至少有一个可变参数)
#define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__)// GNU C 扩展(允许完全省略可变参数)
#define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__)int main() {LOG("Hello, world!\n");  // ✅ GNU C 允许,C99 会报错return 0;
}

在这里插入图片描述
说明:

## 是 标记粘贴运算符,如果 __VA_ARGS__ 为空,它会删除前面的逗号,避免语法错误。

计算可变参数的个数(GNU C 扩展)**

#define COUNT_ARGS(...) sizeof((int[]){__VA_ARGS__}) / sizeof(int)int main() {printf("Number of args: %zu\n", COUNT_ARGS(1, 2, 3, 4));  // 输出 4return 0;
}

注意:

  • 这种方法仅适用于 相同类型的参数(如 int)。
  • 不是标准 C,仅适用于 GCC/Clang。

_Generic + 可变参数宏(C11)

结合 _Generic 实现类型安全的可变参数宏:

#include <stdio.h>#define PRINT_TYPE(x) _Generic((x), \int: printf("%d\n", x), \float: printf("%f\n", x), \char*: printf("%s\n", x) \
)#define PRINT_ALL(...) do { \int arr[] = {__VA_ARGS__}; \for (size_t i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { \PRINT_TYPE(arr[i]); \} \
} while(0)int main() {PRINT_ALL(42, 3.14, "Hello");  // 需要更复杂的实现return 0;
}

说明:

  • 这个例子只是示意,实际实现需要更复杂的宏技巧。

可变参数宏的常见用途

  1. 日志系统
    #define LOG_INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt, ##__VA_ARGS__)
    
  2. 调试输出
    #define DBG_PRINT(...) printf("[DEBUG] %s:%d: ", __FILE__, __LINE__); \printf(__VA_ARGS__)
    
  3. 泛型容器操作
    #define FOREACH(item, ...) \for (int keep = 1, count = 0; keep && count != sizeof((int[]){__VA_ARGS__})/sizeof(int); \keep = !keep, count++) \for (item = ((int[]){__VA_ARGS__})[count]; keep; keep = !keep)
    

注意事项

  1. 标准 C (C99) 要求至少一个可变参数,但 GNU C 允许零个。
  2. 避免参数副作用(如 LOG("%d", i++) 可能导致多次求值)。
  3. 调试困难,因为宏在预处理阶段展开,错误信息可能难以理解。
  4. 可读性差,复杂的可变参数宏可能难以维护。

总结

特性说明
...定义可变参数
__VA_ARGS__引用可变参数
##__VA_ARGS__允许省略可变参数(GNU C)
_Generic + 可变宏类型安全可变参数(C11)
do-while(0)包裹多语句宏

最佳实践:

  • 优先使用 函数 替代复杂宏。
  • 如果必须用宏,确保 可读性安全性
  • 在跨平台代码中,避免依赖 GNU C 扩展(如 ##__VA_ARGS__)。

可变参数宏非常强大,但需要谨慎使用!

常用预定义宏

__LINE__      // 当前行号
__FILE__      // 当前文件名
__DATE__      // 编译日期
__TIME__      // 编译时间
__STDC__      // 如果编译器符合ANSI C标准则为1
__func__      // 当前函数名 (C99)

下面是对这些预定义宏的具体用法示例,每个宏都附带一个完整的代码示例和输出说明:


1. __LINE__ - 当前行号

#include <stdio.h>int main() {printf("This line is at: %d\n", __LINE__);  // 输出当前行号printf("Now we're at line: %d\n", __LINE__); // 行号+1return 0;
}

输出示例:

This line is at: 4
Now we're at line: 5

2. __FILE__ - 当前文件名

#include <stdio.h>int main() {printf("This code is in file: %s\n", __FILE__);return 0;
}

输出示例:

This code is in file: example.c

3. __DATE__ - 编译日期(格式 “MMM DD YYYY”)

#include <stdio.h>int main() {printf("This program was compiled on: %s\n", __DATE__);return 0;
}

输出示例:

This program was compiled on: Jun 15 2023

4. __TIME__ - 编译时间(格式 “HH:MM:SS”)

#include <stdio.h>int main() {printf("Compilation time: %s\n", __TIME__);return 0;
}

输出示例:

Compilation time: 14:30:45

5. __STDC__ - 是否遵循 ANSI C 标准

#include <stdio.h>int main() {#if __STDC__printf("This compiler is ANSI C compliant\n");#elseprintf("This compiler is NOT ANSI C compliant\n");#endifreturn 0;
}

典型输出(现代编译器):

This compiler is ANSI C compliant

6. __func__ - 当前函数名(C99)

#include <stdio.h>void my_function() {printf("Current function: %s\n", __func__);
}int main() {printf("Entering %s\n", __func__);my_function();return 0;
}

输出:

Entering main
Current function: my_function

综合示例:调试日志宏

#include <stdio.h>#define LOG(msg) printf("[%s] %s (Line %d in %s): %s\n", \__TIME__, __func__, __LINE__, __FILE__, msg)int main() {LOG("Program started");if (1) {LOG("Inside conditional block");}return 0;
}

输出示例:

[14:30:45] main (Line 7 in example.c): Program started
[14:30:45] main (Line 9 in example.c): Inside conditional block

关键点总结

作用输出示例标准支持
__LINE__当前行号42C89
__FILE__源文件名"example.c"C89
__DATE__编译日期"Jun 15 2023"C89
__TIME__编译时间"14:30:45"C89
__STDC__ANSI C 合规1C89
__func__函数名"main"C99

注意事项:

  1. __func__ 是 C99 引入的,不是字符串字面量(不能直接拼接)
  2. 所有带下划线的宏由编译器预定义,不可修改
  3. 在调试和日志系统中特别有用

条件编译

C语言条件编译详解

条件编译是C语言预处理器提供的一项重要功能,它允许程序员在编译时根据不同的条件选择性地包含或排除代码段。条件编译在跨平台开发、调试代码、功能开关等场景中非常有用。

基本条件编译指令

1. #ifdef / #ifndef / #endif

#ifdef MACRO_NAME// 如果定义了MACRO_NAME,则编译这部分代码
#endif#ifndef MACRO_NAME// 如果没有定义MACRO_NAME,则编译这部分代码
#endif

示例:

#define DEBUG  // 定义DEBUG宏#ifdef DEBUGprintf("Debug information\n");
#endif#ifndef RELEASEprintf("Not in release mode\n");
#endif

2. #if / #elif / #else / #endif

#if 表达式// 如果表达式为真,编译这部分代码
#elif 其他表达式// 如果前面的表达式为假且这个表达式为真,编译这部分代码
#else// 如果所有表达式都为假,编译这部分代码
#endif

示例:

#define VERSION 3#if VERSION == 1printf("Version 1\n");
#elif VERSION == 2printf("Version 2\n");
#elif VERSION == 3printf("Version 3\n");
#elseprintf("Unknown version\n");
#endif

常见应用场景

1. 跨平台开发

#ifdef _WIN32// Windows平台专用代码#include <windows.h>
#elif __linux__// Linux平台专用代码#include <unistd.h>
#elif __APPLE__// macOS平台专用代码#include <TargetConditionals.h>
#endif

2. 调试代码

#define DEBUG_MODE 1#if DEBUG_MODE#define DEBUG_PRINT(fmt, ...) printf("[DEBUG] " fmt, ##__VA_ARGS__)
#else#define DEBUG_PRINT(fmt, ...) // 定义为空,不产生任何代码
#endifint main() {DEBUG_PRINT("This is debug info: %d\n", 42);return 0;
}

3. 功能开关

#define FEATURE_A_ENABLED 1
#define FEATURE_B_ENABLED 0#if FEATURE_A_ENABLEDvoid feature_a() {printf("Feature A is enabled\n");}
#endif#if FEATURE_B_ENABLEDvoid feature_b() {printf("Feature B is enabled\n");}
#endifint main() {#if FEATURE_A_ENABLEDfeature_a();#endif#if FEATURE_B_ENABLEDfeature_b();#endifreturn 0;
}

预定义宏与条件编译

C语言提供了一些预定义宏,常用于条件编译:

#if __STDC_VERSION__ >= 201112L// C11或更高版本代码
#elif __STDC_VERSION__ >= 199901L// C99代码
#else// C89代码
#endif

实用技巧

1. 宏定义检查

#if defined(MACRO1) && !defined(MACRO2)// 如果定义了MACRO1且没有定义MACRO2
#endif

2. 防止头文件重复包含

// myheader.h
#ifndef MYHEADER_H
#define MYHEADER_H// 头文件内容#endif // MYHEADER_H

3. 编译器特定指令

#ifdef __GNUC__// GCC编译器特有代码#define likely(x)       __builtin_expect(!!(x), 1)#define unlikely(x)     __builtin_expect(!!(x), 0)
#else// 其他编译器#define likely(x)       (x)#define unlikely(x)     (x)
#endif

注意事项

  1. 条件编译指令必须在函数体外使用
  2. 表达式必须是常量表达式
  3. 过度使用条件编译会使代码难以维护
  4. 确保所有条件分支都有正确的#endif匹配

高级用法

1. 宏参数的条件编译

#define CONFIG(opt) (defined(CONFIG_##opt) && CONFIG_##opt)#if CONFIG(DEBUG)printf("Debug mode enabled\n");
#endif

2. 静态断言(C11之前)

#define STATIC_ASSERT(expr, msg) \typedef char static_assertion_##msg[(expr) ? 1 : -1]STATIC_ASSERT(sizeof(int) == 4, int_size_must_be_4_bytes);

条件编译是C语言中非常强大的功能,合理使用可以大大提高代码的灵活性和可移植性。

http://www.dtcms.com/wzjs/52194.html

相关文章:

  • 泰州网站制作策划今日北京新闻
  • 3.建设营销型网站流程.市场seo是什么意思
  • 做新房坐哪个网站好网推项目
  • 自己做网站 需要服务器吗正在直播足球比赛
  • 做网站都能用什么做葫岛百度seo
  • 河南头条最新消息 新闻系统优化软件哪个好
  • 网站升级停止访问如何做提高网站搜索排名
  • 前几年做啥网站致富直通车推广怎么做
  • 企业官方网站管理制度新媒体运营岗位职责
  • 网站菜单分类怎么做的搜索引擎优化概述
  • 怎么做免费的网站推广视频网站推广
  • 杭州网站seo推广软件时事新闻最新2022
  • 网站定制化开发seo实战密码电子书
  • 昆明网站优化公司识万物扫一扫
  • 做徽章标牌的企业网站真人seo点击平台
  • 法院内部网站建设方案seo网站推广的主要目的包括
  • 云南响应式网站建设企业网络营销方法
  • 网站 url 如何设计网上销售哪些平台免费
  • 广州建设信息网官方网站百度知道问答平台
  • 做seo推广公司网站如何推销产品给客户
  • 优秀网站开发微信推广引流平台
  • 武汉今天特大新闻长春做网络优化的公司
  • 定制类网站建设什么叫友情链接
  • php网站 关键技术企业网站营销的典型案例
  • 怎样做赌博网站优化落实防控措施
  • 北京网络营销咨询公司企业网站排名优化公司
  • 我想给别人做网站百度经验官网
  • 网站建设服务费属于什么费用百度秒收录蜘蛛池
  • 做爰全过程免费的教网站网站如何发布
  • 网站系统开发流程中山360推广