C语言
C 语言,是一种通用的、过程式的编程语言,广泛用于系统与应用软件的开发。具有高效、灵活、功能丰富、表达力强和较高的移植性等特点,在程序员中备受青睐。
C 语言是由 UNIX 的研制者丹尼斯·里奇(Dennis Ritchie)和肯·汤普逊(Ken Thompson)于 1970 年研制出的B语言的基础上发展和完善起来的。目前,C 语言编译器普遍存在于各种不同的操作系统中,例如 UNIX、MS-DOS、Microsoft Windows 及 Linux 等。C 语言的设计影响了许多后来的编程语言,例如 C++、Objective-C、Java、C# 等。

查看更多相关内容
C语言中结构体对齐和内存填充是如何工作的?C语言中结构体对齐和内存填充是如何工作的?
**内存对齐原理:**
1. **对齐规则**
- 结构体成员按照其自然边界对齐
- char: 1字节对齐
- short: 2字节对齐
- int: 4字节对齐
- double: 8字节对齐(64位系统)
2. **结构体总大小**
- 必须是其最大成员大小的整数倍
- 末尾可能需要填充字节
**示例分析:**
```c
struct Example1 {
char c; // 1字节 + 3字节填充
int i; // 4字节
}; // 总大小: 8字节
struct Example2 {
char c1; // 1字节 + 1字节填充
short s; // 2字节
int i; // 4字节
}; // 总大小: 8字节
struct Example3 {
char c1; // 1字节 + 7字节填充
double d; // 8字节
char c2; // 1字节 + 7字节填充
}; // 总大小: 24字节
```
**优化技巧:**
1. **成员排序优化**
- 按大小降序排列成员
- 减少填充字节浪费
2. **使用编译器指令**
```c
#pragma pack(1) // 1字节对齐
struct Packed {
char c;
int i;
};
#pragma pack() // 恢复默认对齐
```
3. **位域使用**
```c
struct BitField {
unsigned int a : 3; // 3位
unsigned int b : 5; // 5位
};
```
**注意事项:**
- 不同平台对齐规则可能不同
- 过度紧凑可能影响访问性能
- 网络传输时需考虑字节序和对齐
服务端 · 2月18日 17:22
C语言中内存泄漏的常见原因和检测方法有哪些?C语言中内存泄漏的常见原因和检测方法有哪些?
**常见内存泄漏原因:**
1. **未释放动态分配的内存**
```c
void leak_example() {
int *ptr = malloc(sizeof(int) * 100);
// 忘记调用 free(ptr)
}
```
2. **重复释放导致的双重释放**
```c
int *ptr = malloc(sizeof(int));
free(ptr);
free(ptr); // 未定义行为
```
3. **指针覆盖导致原内存无法释放**
```c
int *ptr = malloc(sizeof(int) * 10);
ptr = malloc(sizeof(int) * 20); // 原内存泄漏
```
4. **循环引用中的内存泄漏**
- 结构体相互引用形成闭环
- 引用计数无法归零
5. **异常处理路径未释放内存**
- 函数中途返回忘记释放
- 错误处理分支遗漏 free 调用
**检测方法:**
1. **Valgrind 工具**
```bash
valgrind --leak-check=full --show-leak-kinds=all ./program
```
2. **AddressSanitizer**
```bash
gcc -fsanitize=address -g program.c -o program
```
3. **代码审查**
- 检查所有 malloc/calloc/realloc 是否有对应 free
- 审查所有函数返回路径的内存释放情况
**预防措施:**
- 使用 RAII 模式(C++风格)
- 建立内存分配释放配对检查机制
- 使用智能指针封装(C++)
- 定期进行内存分析工具检查
服务端 · 2月18日 17:22
C语言中枚举类型的定义和使用技巧有哪些?C语言中枚举类型的定义和使用技巧有哪些?
**枚举类型基础:**
1. **基本定义**
```c
enum Color {
RED,
GREEN,
BLUE
};
enum Color c = RED;
```
2. **指定值**
```c
enum Status {
SUCCESS = 0,
ERROR = -1,
PENDING = 1,
COMPLETED = 2
};
```
3. **匿名枚举**
```c
enum {
MAX_SIZE = 100,
BUFFER_SIZE = 1024
};
```
**高级用法:**
1. **枚举作为位标志**
```c
enum FileFlags {
READ = 0x01, // 0001
WRITE = 0x02, // 0010
EXECUTE = 0x04, // 0100
APPEND = 0x08 // 1000
};
unsigned int flags = READ | WRITE;
if (flags & READ) {
printf("Read permission\n");
}
```
2. **枚举与switch配合**
```c
enum Day {
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
};
void print_day(enum Day day) {
switch (day) {
case MONDAY:
printf("Monday\n");
break;
case TUESDAY:
printf("Tuesday\n");
break;
default:
printf("Other day\n");
}
}
```
3. **枚举类型转换**
```c
enum Color { RED, GREEN, BLUE };
// 枚举到整数
int value = RED; // value = 0
// 整数到枚举
enum Color c = (enum Color)1; // GREEN
// 枚举大小
printf("Size of enum: %zu\n", sizeof(enum Color));
```
**最佳实践:**
1. **命名约定**
```c
// 使用大写和下划线
enum ErrorCode {
ERROR_NONE,
ERROR_INVALID_PARAM,
ERROR_OUT_OF_MEMORY,
ERROR_FILE_NOT_FOUND
};
// 或使用前缀
enum SocketType {
SOCK_TYPE_STREAM,
SOCK_TYPE_DGRAM
};
```
2. **枚举作为数组索引**
```c
enum Month {
JAN = 1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC
};
const char* month_names[] = {
"", "January", "February", "March",
"April", "May", "June", "July",
"August", "September", "October",
"November", "December"
};
printf("%s\n", month_names[JAN]);
```
3. **枚举与typedef结合**
```c
typedef enum {
STATE_IDLE,
STATE_RUNNING,
STATE_PAUSED,
STATE_STOPPED
} State;
State current_state = STATE_IDLE;
```
**注意事项:**
1. **枚举值的连续性**
```c
enum Example {
A = 1,
B = 2,
C = 5, // 不连续
D = 6
};
// 不能假设枚举值是连续的
```
2. **枚举的范围**
```c
enum Small {
MIN = 0,
MAX = 255
};
// 编译器可能选择更大的类型
// 不能保证只占用1字节
```
3. **枚举的前向声明**
```c
// C11 支持
enum Color;
void process_color(enum Color c);
enum Color {
RED, GREEN, BLUE
};
```
**实际应用示例:**
1. **状态机实现**
```c
typedef enum {
STATE_INIT,
STATE_CONNECTING,
STATE_CONNECTED,
STATE_DISCONNECTING,
STATE_ERROR
} ConnectionState;
ConnectionState handle_state(ConnectionState state) {
switch (state) {
case STATE_INIT:
return STATE_CONNECTING;
case STATE_CONNECTING:
return STATE_CONNECTED;
case STATE_CONNECTED:
return STATE_DISCONNECTING;
default:
return STATE_ERROR;
}
}
```
2. **配置选项**
```c
enum ConfigOption {
OPT_DEBUG = 0x01,
OPT_VERBOSE = 0x02,
OPT_LOG_FILE = 0x04,
OPT_DAEMON = 0x08
};
void configure(unsigned int options) {
if (options & OPT_DEBUG) {
enable_debug();
}
if (options & OPT_DAEMON) {
run_as_daemon();
}
}
```
3. **错误码定义**
```c
enum LibraryError {
LIB_OK = 0,
LIB_ERR_INVALID_ARG = -1,
LIB_ERR_OUT_OF_MEMORY = -2,
LIB_ERR_IO = -3,
LIB_ERR_TIMEOUT = -4
};
enum LibraryError library_init() {
if (!allocate_memory()) {
return LIB_ERR_OUT_OF_MEMORY;
}
return LIB_OK;
}
```
服务端 · 2月18日 17:22
C语言中结构体和类的区别及使用场景是什么?C语言中结构体和类的区别及使用场景是什么?
**结构体基本概念:**
1. **结构体定义**
```c
struct Point {
int x;
int y;
};
struct Point p1 = {10, 20};
struct Point p2 = {.x = 30, .y = 40};
```
2. **结构体指针**
```c
struct Point *ptr = &p1;
ptr->x = 50;
ptr->y = 60;
```
**与类的对比:**
1. **数据封装**
```c
// C语言结构体
struct Rectangle {
int width;
int height;
};
// C++类
class Rectangle {
private:
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
int area() { return width * height; }
};
```
2. **方法定义**
```c
// C语言:使用函数指针
struct Shape {
int (*area)(struct Shape*);
int (*perimeter)(struct Shape*);
};
int rectangle_area(struct Shape *s) {
struct Rectangle *r = (struct Rectangle*)s;
return r->width * r->height;
}
// C++:成员函数
class Shape {
public:
virtual int area() = 0;
virtual int perimeter() = 0;
};
```
3. **构造和析构**
```c
// C语言:手动初始化
struct Point create_point(int x, int y) {
struct Point p = {x, y};
return p;
}
void destroy_point(struct Point *p) {
// 手动清理资源
}
// C++:自动构造和析构
class Point {
public:
Point(int x, int y) : x(x), y(y) {}
~Point() {}
private:
int x, y;
};
```
**使用场景:**
1. **数据结构**
```c
struct Node {
int data;
struct Node *next;
};
struct LinkedList {
struct Node *head;
int size;
};
```
2. **配置管理**
```c
struct Config {
char server[256];
int port;
int timeout;
int max_connections;
};
struct Config load_config(const char *filename);
```
3. **网络协议**
```c
struct PacketHeader {
unsigned int version : 4;
unsigned int type : 4;
unsigned int length : 16;
unsigned int checksum : 8;
};
```
**高级特性:**
1. **结构体嵌套**
```c
struct Address {
char street[100];
char city[50];
char country[50];
};
struct Person {
char name[50];
int age;
struct Address address;
};
struct Person person = {
.name = "John Doe",
.age = 30,
.address = {
.street = "123 Main St",
.city = "New York",
.country = "USA"
}
};
```
2. **结构体数组**
```c
struct Student {
int id;
char name[50];
float score;
};
struct Student students[100];
students[0].id = 1;
strcpy(students[0].name, "Alice");
students[0].score = 95.5;
```
3. **灵活数组成员**
```c
struct String {
size_t length;
char data[]; // 灵活数组成员
};
struct String *create_string(const char *str) {
size_t len = strlen(str);
struct String *s = malloc(sizeof(struct String) + len + 1);
s->length = len;
strcpy(s->data, str);
return s;
}
```
**最佳实践:**
1. **命名约定**
```c
struct Point {
int x;
int y;
};
typedef struct Point Point;
Point p1 = {10, 20};
```
2. **初始化函数**
```c
struct Point point_create(int x, int y) {
struct Point p = {x, y};
return p;
}
struct Point p = point_create(10, 20);
```
3. **内存管理**
```c
struct Point *point_alloc(int x, int y) {
struct Point *p = malloc(sizeof(struct Point));
if (p) {
p->x = x;
p->y = y;
}
return p;
}
void point_free(struct Point *p) {
free(p);
}
```
**注意事项:**
1. **内存对齐**
```c
struct Example {
char c; // 1字节 + 3字节填充
int i; // 4字节
}; // 总大小: 8字节
```
2. **结构体赋值**
```c
struct Point p1 = {10, 20};
struct Point p2 = p1; // 浅拷贝
```
3. **结构体比较**
```c
struct Point p1 = {10, 20};
struct Point p2 = {10, 20};
// 错误:不能直接比较结构体
// if (p1 == p2) { }
// 正确:逐个成员比较
if (p1.x == p2.x && p1.y == p2.y) {
printf("Equal\n");
}
```
服务端 · 2月18日 17:22
C语言中动态内存管理的完整指南和常见问题是什么?C语言中动态内存管理的完整指南和常见问题是什么?
**动态内存分配函数:**
1. **malloc - 分配内存**
```c
void *malloc(size_t size);
// 分配指定字节数的内存
int *arr = (int*)malloc(10 * sizeof(int));
if (arr == NULL) {
fprintf(stderr, "Memory allocation failed\n");
exit(1);
}
// 使用内存
for (int i = 0; i < 10; i++) {
arr[i] = i * i;
}
// 释放内存
free(arr);
```
2. **calloc - 分配并初始化**
```c
void *calloc(size_t num, size_t size);
// 分配并初始化为零
int *arr = (int*)calloc(10, sizeof(int));
// 所有元素自动初始化为0
free(arr);
```
3. **realloc - 重新分配**
```c
void *realloc(void *ptr, size_t size);
int *arr = (int*)malloc(5 * sizeof(int));
// 扩展内存
int *new_arr = (int*)realloc(arr, 10 * sizeof(int));
if (new_arr == NULL) {
free(arr); // 原内存仍然有效
exit(1);
}
arr = new_arr;
free(arr);
```
4. **free - 释放内存**
```c
void free(void *ptr);
int *ptr = (int*)malloc(sizeof(int));
free(ptr);
ptr = NULL; // 避免悬空指针
```
**内存管理最佳实践:**
1. **检查分配结果**
```c
void *ptr = malloc(size);
if (ptr == NULL) {
// 处理内存分配失败
return NULL;
}
```
2. **避免内存泄漏**
```c
void function_with_leak() {
int *ptr = malloc(sizeof(int));
// 忘记 free(ptr) - 内存泄漏
}
void correct_function() {
int *ptr = malloc(sizeof(int));
if (ptr) {
// 使用内存
free(ptr);
}
}
```
3. **防止悬空指针**
```c
int *ptr = malloc(sizeof(int));
free(ptr);
ptr = NULL; // 避免使用已释放的内存
// 错误示例
*ptr = 10; // 未定义行为
```
4. **双重释放防护**
```c
int *ptr = malloc(sizeof(int));
free(ptr);
ptr = NULL; // 设置为NULL
free(ptr); // free(NULL) 是安全的
```
**常见问题和解决方案:**
1. **内存碎片**
```c
// 问题:频繁分配和释放不同大小的内存
for (int i = 0; i < 1000; i++) {
void *ptr = malloc(rand() % 1000);
free(ptr);
}
// 解决:使用内存池或固定大小分配
```
2. **缓冲区溢出**
```c
// 危险
int *arr = malloc(10 * sizeof(int));
arr[10] = 100; // 越界访问
// 安全
int *arr = malloc(10 * sizeof(int));
if (index < 10) {
arr[index] = value;
}
```
3. **野指针**
```c
int *ptr; // 未初始化
*ptr = 10; // 未定义行为
// 正确做法
int *ptr = NULL;
ptr = malloc(sizeof(int));
if (ptr) {
*ptr = 10;
free(ptr);
ptr = NULL;
}
```
**高级技巧:**
1. **自定义内存分配器**
```c
void* my_malloc(size_t size) {
void *ptr = malloc(size);
if (ptr) {
memset(ptr, 0, size); // 清零
}
return ptr;
}
```
2. **内存调试**
```c
#ifdef DEBUG
void *debug_malloc(size_t size, const char *file, int line) {
void *ptr = malloc(size);
printf("Allocated %zu bytes at %p (%s:%d)\n",
size, ptr, file, line);
return ptr;
}
#define MALLOC(size) debug_malloc(size, __FILE__, __LINE__)
#else
#define MALLOC(size) malloc(size)
#endif
```
服务端 · 2月18日 17:21
C语言中typedef和#define的区别及使用场景是什么?C语言中typedef和#define的区别及使用场景是什么?
**核心区别:**
1. **处理阶段**
- `#define`: 预处理器阶段,文本替换
- `typedef`: 编译器阶段,类型别名
2. **作用域**
- `#define`: 全局作用域,从定义点到文件末尾
- `typedef`: 遵循正常作用域规则
3. **类型检查**
- `#define`: 无类型检查,纯文本替换
- `typedef`: 有类型检查,编译器验证
4. **调试支持**
- `#define`: 调试时显示原始代码
- `typedef`: 调试时显示别名类型
**使用场景对比:**
1. **类型别名**
```c
// typedef - 推荐
typedef unsigned int uint32_t;
uint32_t value = 100;
// #define - 不推荐
#define uint32_t unsigned int
uint32_t value = 100;
```
2. **函数指针**
```c
// typedef - 清晰易读
typedef int (*CompareFunc)(const void*, const void*);
CompareFunc compare = my_compare;
// #define - 难以理解
#define CompareFunc int (*)(const void*, const void*)
CompareFunc compare = my_compare;
```
3. **结构体**
```c
// typedef - 简洁
typedef struct {
int x;
int y;
} Point;
Point p1 = {10, 20};
// #define - 不适用
```
4. **数组类型**
```c
// typedef - 类型安全
typedef int Array10[10];
Array10 arr1, arr2;
// #define - 可能导致意外行为
#define Array10 int[10]
Array10 arr1, arr2; // 只有arr2是数组
```
**#define 的优势场景:**
1. **常量定义**
```c
#define MAX_SIZE 100
#define PI 3.14159
#define VERSION "1.0.0"
```
2. **条件编译**
```c
#ifdef DEBUG
#define LOG(x) printf x
#else
#define LOG(x)
#endif
```
3. **宏函数**
```c
#define SQUARE(x) ((x) * (x))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
```
**typedef 的优势场景:**
1. **提高代码可读性**
```c
typedef unsigned long long ull;
typedef struct Node* NodePtr;
```
2. **跨平台兼容性**
```c
#ifdef _WIN64
typedef __int64 intptr_t;
#else
typedef long intptr_t;
#endif
```
3. **回调函数类型**
```c
typedef void (*Callback)(int result);
void register_callback(Callback cb);
```
**常见陷阱:**
1. **宏的副作用**
```c
#define SQUARE(x) ((x) * (x))
int i = 2;
int result = SQUARE(i++); // 未定义行为
```
2. **宏的括号问题**
```c
#define MUL(a, b) a * b
int result = MUL(2 + 3, 4); // 结果是14,不是20
```
3. **typedef 不能用于数组初始化**
```c
typedef int IntArray[10];
IntArray arr = {1, 2, 3}; // 错误
int arr[10] = {1, 2, 3}; // 正确
```
服务端 · 2月18日 17:21
C语言中联合体(union)的使用场景和内存布局是什么?C语言中联合体(union)的使用场景和内存布局是什么?
**联合体基本概念:**
1. **定义和声明**
```c
union Data {
int i;
float f;
char str[20];
};
union Data data;
data.i = 10;
data.f = 3.14;
strcpy(data.str, "Hello");
```
2. **内存共享特性**
```c
union Example {
int value;
char bytes[4];
};
union Example ex;
ex.value = 0x12345678;
// bytes[0] = 0x78 (小端序)
// bytes[1] = 0x56
// bytes[2] = 0x34
// bytes[3] = 0x12
```
**典型使用场景:**
1. **数据类型转换**
```c
union FloatInt {
float f;
unsigned int i;
};
float_to_bits(float value) {
union FloatInt converter;
converter.f = value;
return converter.i;
}
```
2. **节省内存空间**
```c
// 不使用联合体:占用12字节
struct Message {
int type;
union {
int int_data;
float float_data;
char char_data[4];
} data;
};
// 使用联合体:只占用8字节
union CompactMessage {
struct {
int type;
int data;
} int_msg;
struct {
int type;
float data;
} float_msg;
};
```
3. **网络协议解析**
```c
union IPHeader {
struct {
unsigned int version : 4;
unsigned int ihl : 4;
unsigned int tos : 8;
unsigned int total_length : 16;
} fields;
unsigned int raw;
};
```
4. **变体数据类型**
```c
enum DataType { INT, FLOAT, STRING };
struct Variant {
enum DataType type;
union {
int int_val;
float float_val;
char *str_val;
} value;
};
```
**内存布局分析:**
1. **大小计算**
```c
union SizeExample {
char c; // 1字节
int i; // 4字节
double d; // 8字节
};
sizeof(union SizeExample); // 8字节(最大成员的大小)
```
2. **对齐规则**
```c
union AlignedExample {
char c;
int i;
double d;
};
// 大小为8字节,对齐到8字节边界
```
**高级应用:**
1. **位域操作**
```c
union BitManipulation {
unsigned int value;
struct {
unsigned int bit0 : 1;
unsigned int bit1 : 1;
unsigned int bit2 : 1;
unsigned int rest : 29;
} bits;
};
union BitManipulation bm;
bm.value = 0;
bm.bits.bit0 = 1;
```
2. **类型安全的联合体**
```c
struct SafeUnion {
enum { INT, FLOAT, STRING } type;
union {
int int_val;
float float_val;
char *str_val;
} data;
};
void print_safe_union(struct SafeUnion *su) {
switch (su->type) {
case INT:
printf("%d\n", su->data.int_val);
break;
case FLOAT:
printf("%f\n", su->data.float_val);
break;
case STRING:
printf("%s\n", su->data.str_val);
break;
}
}
```
**注意事项:**
1. **同时访问问题**
```c
union Data {
int i;
float f;
};
union Data d;
d.i = 10;
d.f = 3.14; // 覆盖了之前的值
// 此时访问 d.i 是未定义行为
```
2. **字节序依赖**
```c
union EndianTest {
int value;
char bytes[4];
};
union EndianTest test;
test.value = 1;
if (test.bytes[0] == 1) {
printf("Little Endian\n");
} else {
printf("Big Endian\n");
}
```
3. **初始化**
```c
union Data {
int i;
float f;
};
union Data d1 = {10}; // 初始化第一个成员
union Data d2 = {.f = 3.14}; // 指定成员初始化
```
服务端 · 2月18日 17:21
C语言中字符串处理函数的完整列表和最佳实践是什么?C语言中字符串处理函数的完整列表和最佳实践是什么?
**核心字符串函数:**
1. **字符串长度**
```c
size_t strlen(const char *str);
// 返回字符串长度,不包含终止符 '\0'
```
2. **字符串复制**
```c
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
// strncpy 不会自动添加 '\0',需要手动处理
```
3. **字符串连接**
```c
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
// 确保目标缓冲区足够大
```
4. **字符串比较**
```c
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
// 返回值:0表示相等,<0表示s1<s2,>0表示s1>s2
```
5. **字符串查找**
```c
char *strchr(const char *str, int c); // 查找字符首次出现
char *strrchr(const char *str, int c); // 查找字符最后出现
char *strstr(const char *haystack, const char *needle); // 查找子串
```
6. **字符串分割**
```c
char *strtok(char *str, const char *delim);
// 注意:strtok 会修改原字符串,且不是线程安全的
```
7. **安全版本(C11)**
```c
errno_t strcpy_s(char *dest, rsize_t destsz, const char *src);
errno_t strcat_s(char *dest, rsize_t destsz, const char *src);
```
**最佳实践:**
1. **缓冲区溢出防护**
```c
// 不安全
strcpy(dest, src);
// 安全方式
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
```
2. **字符串拼接安全**
```c
char buffer[100];
snprintf(buffer, sizeof(buffer), "%s%s", str1, str2);
```
3. **动态字符串处理**
```c
char *safe_strdup(const char *str) {
if (!str) return NULL;
size_t len = strlen(str) + 1;
char *copy = malloc(len);
if (copy) memcpy(copy, str, len);
return copy;
}
```
4. **字符串格式化**
```c
char buffer[256];
int result = snprintf(buffer, sizeof(buffer), "Value: %d", value);
if (result < 0 || result >= sizeof(buffer)) {
// 处理错误
}
```
**常见陷阱:**
- 忘记为 '\0' 预留空间
- 使用未初始化的字符串
- 混淆 strlen 和 sizeof
- 忽略函数返回值
- 多次调用 strtok 时的状态问题
服务端 · 2月18日 17:21
C语言中预处理器指令的完整列表和使用场景有哪些?C语言中预处理器指令的完整列表和使用场景有哪些?
**核心预处理器指令:**
1. **文件包含 #include**
```c
#include <stdio.h> // 系统头文件
#include "myheader.h" // 用户头文件
// 条件包含
#if defined(USE_FEATURE)
#include "feature.h"
#endif
```
2. **宏定义 #define**
```c
// 简单宏
#define PI 3.14159
#define MAX_SIZE 100
// 带参数的宏
#define SQUARE(x) ((x) * (x))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
// 字符串化
#define STR(x) #x
#define PRINT_VAR(var) printf(#var " = %d\n", var)
// 连接
#define CONCAT(a, b) a##b
```
3. **条件编译**
```c
#if defined(UNIX)
#include <unistd.h>
#elif defined(WINDOWS)
#include <windows.h>
#else
#error "Unsupported platform"
#endif
#ifdef DEBUG
#define LOG(x) printf x
#else
#define LOG(x)
#endif
```
4. **错误和警告**
```c
#if SIZE < 0
#error "Size must be positive"
#endif
#if !defined(VERSION)
#warning "VERSION not defined, using default"
#define VERSION "1.0"
#endif
```
5. **行控制 #line**
```c
#line 100 "custom.c"
// 错误信息将显示为 custom.c:100
```
6. **编译指示 #pragma**
```c
#pragma once // 防止重复包含
#pragma pack(1) // 内存对齐
#pragma warning(disable:4996) // 禁用警告
```
7. **取消定义 #undef**
```c
#define TEMP 100
#undef TEMP
```
**高级应用场景:**
1. **跨平台兼容性**
```c
#if defined(_WIN32) || defined(_WIN64)
#define PATH_SEPARATOR '\\'
#else
#define PATH_SEPARATOR '/'
#endif
```
2. **调试和日志**
```c
#ifdef DEBUG
#define DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define DEBUG_PRINT(fmt, ...)
#endif
```
3. **版本控制**
```c
#define VERSION_MAJOR 2
#define VERSION_MINOR 5
#define VERSION_STRING "2.5"
```
**注意事项:**
- 宏没有类型检查
- 宏展开可能导致意外的副作用
- 优先使用 const 和 inline 函数替代宏
服务端 · 2月18日 17:21
C语言中预定义宏和条件编译的完整用法是什么?C语言中预定义宏和条件编译的完整用法是什么?
**预定义宏:**
1. **标准预定义宏**
```c
void print_predefined_macros() {
printf("File: %s\n", __FILE__);
printf("Line: %d\n", __LINE__);
printf("Date: %s\n", __DATE__);
printf("Time: %s\n", __TIME__);
printf("Function: %s\n", __func__);
#ifdef __STDC_VERSION__
printf("C Standard: %ld\n", __STDC_VERSION__);
#endif
}
```
2. **编译器特定宏**
```c
void compiler_specific_code() {
#ifdef __GNUC__
printf("GCC compiler\n");
#elif defined(__clang__)
printf("Clang compiler\n");
#elif defined(_MSC_VER)
printf("MSVC compiler\n");
#endif
}
```
3. **平台检测**
```c
void platform_specific_code() {
#ifdef _WIN32
printf("Windows platform\n");
#elif defined(__linux__)
printf("Linux platform\n");
#elif defined(__APPLE__)
printf("macOS platform\n");
#endif
}
```
**条件编译:**
1. **基本条件编译**
```c
#ifdef DEBUG
#define LOG(x) printf x
#else
#define LOG(x)
#endif
void function() {
LOG(("Debug message\n"));
}
```
2. **多重条件**
```c
#if defined(UNIX) && !defined(DEBUG)
#define OPTIMIZED_CODE
#endif
#if VERSION >= 2
#include "new_features.h"
#else
#include "legacy_features.h"
#endif
```
3. **错误和警告**
```c
#if SIZE < 0
#error "Size must be positive"
#endif
#if !defined(VERSION)
#warning "VERSION not defined, using default"
#define VERSION "1.0"
#endif
```
**高级用法:**
1. **宏字符串化**
```c
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
printf("Line: %s\n", TOSTRING(__LINE__));
```
2. **宏连接**
```c
#define CONCAT(a, b) a##b
int CONCAT(var, 1) = 10; // var1
```
3. **可变参数宏**
```c
#define LOG(fmt, ...) printf("[LOG] " fmt "\n", ##__VA_ARGS__)
LOG("Value: %d", 42);
LOG("Simple message");
```
**实际应用:**
1. **调试宏**
```c
#ifdef DEBUG
#define DEBUG_PRINT(fmt, ...) \
printf("[DEBUG %s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define DEBUG_PRINT(fmt, ...)
#endif
void example_function() {
DEBUG_PRINT("Processing data: %d", 100);
}
```
2. **版本控制**
```c
#define VERSION_MAJOR 2
#define VERSION_MINOR 5
#define VERSION_PATCH 1
#define VERSION_STRING \
TOSTRING(VERSION_MAJOR) "." \
TOSTRING(VERSION_MINOR) "." \
TOSTRING(VERSION_PATCH)
printf("Version: %s\n", VERSION_STRING);
```
3. **跨平台代码**
```c
#ifdef _WIN32
#define PATH_SEPARATOR '\\'
#define PATH_SEPARATOR_STR "\\"
#else
#define PATH_SEPARATOR '/'
#define PATH_SEPARATOR_STR "/"
#endif
void join_path(char *dest, const char *dir, const char *file) {
sprintf(dest, "%s%s%s", dir, PATH_SEPARATOR_STR, file);
}
```
4. **功能开关**
```c
#define FEATURE_A_ENABLED 1
#define FEATURE_B_ENABLED 0
void process_data() {
#if FEATURE_A_ENABLED
feature_a_process();
#endif
#if FEATURE_B_ENABLED
feature_b_process();
#endif
}
```
**最佳实践:**
1. **头文件保护**
```c
#ifndef HEADER_H
#define HEADER_H
// 头文件内容
#endif
```
2. **一次性包含**
```c
#pragma once
// 头文件内容
```
3. **宏作用域控制**
```c
#undef TEMP_MACRO
#define TEMP_MACRO(x) (x * 2)
int result = TEMP_MACRO(5);
#undef TEMP_MACRO
```
**注意事项:**
1. **宏的副作用**
```c
#define SQUARE(x) ((x) * (x))
int i = 2;
int result = SQUARE(i++); // 未定义行为
```
2. **宏的括号**
```c
#define MUL(a, b) ((a) * (b))
int result = MUL(2 + 3, 4); // 正确: (2 + 3) * 4 = 20
```
3. **条件编译的嵌套**
```c
#ifdef DEBUG
#ifdef VERBOSE
#define LOG(x) printf x
#else
#define LOG(x)
#endif
#else
#define LOG(x)
#endif
```
服务端 · 2月18日 17:21