乐闻世界logo
搜索文章和话题

面试题手册

C语言中联合体(union)的使用场景和内存布局是什么?

C语言中联合体(union)的使用场景和内存布局是什么?联合体基本概念:定义和声明 union Data { int i; float f; char str[20]; }; union Data data; data.i = 10; data.f = 3.14; strcpy(data.str, "Hello");内存共享特性 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典型使用场景:数据类型转换 union FloatInt { float f; unsigned int i; }; float_to_bits(float value) { union FloatInt converter; converter.f = value; return converter.i; }节省内存空间 // 不使用联合体:占用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; };网络协议解析 union IPHeader { struct { unsigned int version : 4; unsigned int ihl : 4; unsigned int tos : 8; unsigned int total_length : 16; } fields; unsigned int raw; };变体数据类型 enum DataType { INT, FLOAT, STRING }; struct Variant { enum DataType type; union { int int_val; float float_val; char *str_val; } value; };内存布局分析:大小计算 union SizeExample { char c; // 1字节 int i; // 4字节 double d; // 8字节 }; sizeof(union SizeExample); // 8字节(最大成员的大小)对齐规则 union AlignedExample { char c; int i; double d; }; // 大小为8字节,对齐到8字节边界高级应用:位域操作 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;类型安全的联合体 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; } }注意事项:同时访问问题 union Data { int i; float f; }; union Data d; d.i = 10; d.f = 3.14; // 覆盖了之前的值 // 此时访问 d.i 是未定义行为字节序依赖 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"); }初始化 union Data { int i; float f; }; union Data d1 = {10}; // 初始化第一个成员 union Data d2 = {.f = 3.14}; // 指定成员初始化
阅读 0·2月18日 17:21

C语言中字符串处理函数的完整列表和最佳实践是什么?

C语言中字符串处理函数的完整列表和最佳实践是什么?核心字符串函数:字符串长度 size_t strlen(const char *str); // 返回字符串长度,不包含终止符 '\0'字符串复制 char *strcpy(char *dest, const char *src); char *strncpy(char *dest, const char *src, size_t n); // strncpy 不会自动添加 '\0',需要手动处理字符串连接 char *strcat(char *dest, const char *src); char *strncat(char *dest, const char *src, size_t n); // 确保目标缓冲区足够大字符串比较 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字符串查找 char *strchr(const char *str, int c); // 查找字符首次出现 char *strrchr(const char *str, int c); // 查找字符最后出现 char *strstr(const char *haystack, const char *needle); // 查找子串字符串分割 char *strtok(char *str, const char *delim); // 注意:strtok 会修改原字符串,且不是线程安全的安全版本(C11) errno_t strcpy_s(char *dest, rsize_t destsz, const char *src); errno_t strcat_s(char *dest, rsize_t destsz, const char *src);最佳实践:缓冲区溢出防护 // 不安全 strcpy(dest, src); // 安全方式 strncpy(dest, src, sizeof(dest) - 1); dest[sizeof(dest) - 1] = '\0';字符串拼接安全 char buffer[100]; snprintf(buffer, sizeof(buffer), "%s%s", str1, str2);动态字符串处理 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; }字符串格式化 char buffer[256]; int result = snprintf(buffer, sizeof(buffer), "Value: %d", value); if (result < 0 || result >= sizeof(buffer)) { // 处理错误 }常见陷阱:忘记为 '\0' 预留空间使用未初始化的字符串混淆 strlen 和 sizeof忽略函数返回值多次调用 strtok 时的状态问题
阅读 0·2月18日 17:21

C语言中预处理器指令的完整列表和使用场景有哪些?

C语言中预处理器指令的完整列表和使用场景有哪些?核心预处理器指令:文件包含 #include #include <stdio.h> // 系统头文件 #include "myheader.h" // 用户头文件 // 条件包含 #if defined(USE_FEATURE) #include "feature.h" #endif宏定义 #define // 简单宏 #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条件编译 #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错误和警告 #if SIZE < 0 #error "Size must be positive" #endif #if !defined(VERSION) #warning "VERSION not defined, using default" #define VERSION "1.0" #endif行控制 #line #line 100 "custom.c" // 错误信息将显示为 custom.c:100编译指示 #pragma #pragma once // 防止重复包含 #pragma pack(1) // 内存对齐 #pragma warning(disable:4996) // 禁用警告取消定义 #undef #define TEMP 100 #undef TEMP高级应用场景:跨平台兼容性 #if defined(_WIN32) || defined(_WIN64) #define PATH_SEPARATOR '\\' #else #define PATH_SEPARATOR '/' #endif调试和日志 #ifdef DEBUG #define DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_PRINT(fmt, ...) #endif版本控制 #define VERSION_MAJOR 2 #define VERSION_MINOR 5 #define VERSION_STRING "2.5"注意事项:宏没有类型检查宏展开可能导致意外的副作用优先使用 const 和 inline 函数替代宏
阅读 0·2月18日 17:21

C语言中预定义宏和条件编译的完整用法是什么?

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 }编译器特定宏 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 }平台检测 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 }条件编译:基本条件编译 #ifdef DEBUG #define LOG(x) printf x #else #define LOG(x) #endif void function() { LOG(("Debug message\n")); }多重条件 #if defined(UNIX) && !defined(DEBUG) #define OPTIMIZED_CODE #endif #if VERSION >= 2 #include "new_features.h" #else #include "legacy_features.h" #endif错误和警告 #if SIZE < 0 #error "Size must be positive" #endif #if !defined(VERSION) #warning "VERSION not defined, using default" #define VERSION "1.0" #endif高级用法:宏字符串化 #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) printf("Line: %s\n", TOSTRING(__LINE__));宏连接 #define CONCAT(a, b) a##b int CONCAT(var, 1) = 10; // var1可变参数宏 #define LOG(fmt, ...) printf("[LOG] " fmt "\n", ##__VA_ARGS__) LOG("Value: %d", 42); LOG("Simple message");实际应用:调试宏 #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); }版本控制 #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);跨平台代码 #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); }功能开关 #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 }最佳实践:头文件保护 #ifndef HEADER_H #define HEADER_H // 头文件内容 #endif一次性包含 #pragma once // 头文件内容宏作用域控制 #undef TEMP_MACRO #define TEMP_MACRO(x) (x * 2) int result = TEMP_MACRO(5); #undef TEMP_MACRO注意事项:宏的副作用 #define SQUARE(x) ((x) * (x)) int i = 2; int result = SQUARE(i++); // 未定义行为宏的括号 #define MUL(a, b) ((a) * (b)) int result = MUL(2 + 3, 4); // 正确: (2 + 3) * 4 = 20条件编译的嵌套 #ifdef DEBUG #ifdef VERBOSE #define LOG(x) printf x #else #define LOG(x) #endif #else #define LOG(x) #endif
阅读 0·2月18日 17:21

C语言中位域(bit-field)的定义和使用场景是什么?

C语言中位域(bit-field)的定义和使用场景是什么?位域基本概念:基本定义 struct BitField { unsigned int flag1 : 1; // 1位 unsigned int flag2 : 1; // 1位 unsigned int value : 6; // 6位 unsigned int status : 4; // 4位 }; struct BitField bf; bf.flag1 = 1; bf.value = 42;位域大小 struct Example { unsigned int a : 3; // 0-7 unsigned int b : 5; // 0-31 unsigned int c : 8; // 0-255 }; sizeof(struct Example); // 通常为4字节使用场景:标志位管理 struct FileFlags { unsigned int read : 1; unsigned int write : 1; unsigned int execute : 1; unsigned int hidden : 1; unsigned int system : 1; unsigned int archive : 1; unsigned int reserved : 2; }; struct FileFlags flags = {0}; flags.read = 1; flags.write = 1;协议字段解析 struct IPHeader { unsigned int version : 4; unsigned int ihl : 4; unsigned int tos : 8; unsigned int total_length : 16; unsigned int identification : 16; unsigned int flags : 3; unsigned int fragment_offset : 13; }; struct IPHeader header; header.version = 4; header.ihl = 5;硬件寄存器映射 struct Register { unsigned int enable : 1; unsigned int mode : 2; unsigned int speed : 3; unsigned int reserved : 26; }; volatile struct Register *reg = (volatile struct Register*)0x40000000; reg->enable = 1; reg->mode = 2;颜色编码 struct RGB { unsigned int red : 8; unsigned int green : 8; unsigned int blue : 8; unsigned int alpha : 8; }; struct RGB color = {255, 128, 64, 255};高级特性:命名位域 struct PaddedBitField { unsigned int a : 4; unsigned int : 0; // 填充到下一个边界 unsigned int b : 4; };无名称位域 struct UnnamedBits { unsigned int flag1 : 1; unsigned int : 3; // 跳过3位 unsigned int flag2 : 1; };有符号位域 struct SignedBits { signed int value : 4; // -8 到 7 unsigned int uvalue : 4; // 0 到 15 };注意事项:跨平台兼容性 // 位域的布局依赖于编译器 struct Portable { unsigned int a : 8; unsigned int b : 8; }; // 不同编译器可能有不同的布局位域的地址 struct BitField { unsigned int a : 4; unsigned int b : 4; }; struct BitField bf; // &bf.a 是非法的,不能取位域的地址位域的限制 struct LimitExample { unsigned int value : 3; // 0-7 }; struct LimitExample le; le.value = 10; // 实际存储为 10 % 8 = 2实际应用示例:状态机压缩 struct StateMachine { unsigned int current_state : 3; unsigned int previous_state : 3; unsigned int error_code : 4; unsigned int flags : 6; }; struct StateMachine sm = {0}; sm.current_state = 2; sm.flags = 0x3F;网络数据包解析 struct TCPHeader { unsigned int source_port : 16; unsigned int dest_port : 16; unsigned int sequence_number : 32; unsigned int ack_number : 32; unsigned int data_offset : 4; unsigned int reserved : 3; unsigned int flags : 9; };音频格式描述 struct AudioFormat { unsigned int sample_rate : 4; unsigned int bit_depth : 4; unsigned int channels : 2; unsigned int format : 6; }; struct AudioFormat audio = { .sample_rate = 3, // 44.1kHz .bit_depth = 2, // 16-bit .channels = 1, // Stereo .format = 1 // PCM };
阅读 0·2月18日 17:21

C语言中restrict关键字的用途和优化效果是什么?

C语言中restrict关键字的用途和优化效果是什么?restrict 关键字基本概念:指针别名限制 void copy(int *restrict dest, const int *restrict src, size_t n) { for (size_t i = 0; i < n; i++) { dest[i] = src[i]; } } // dest 和 src 不会指向重叠的内存区域编译器优化 // 没有 restrict void add_arrays(int *a, int *b, int *c, int n) { for (int i = 0; i < n; i++) { a[i] = b[i] + c[i]; } } // 使用 restrict void add_arrays_optimized(int *restrict a, const int *restrict b, const int *restrict c, int n) { for (int i = 0; i < n; i++) { a[i] = b[i] + c[i]; } }使用场景:内存拷贝 void memcpy_custom(void *restrict dest, const void *restrict src, size_t n) { unsigned char *d = dest; const unsigned char *s = src; while (n--) { *d++ = *s++; } }数学运算 void vector_add(double *restrict result, const double *restrict a, const double *restrict b, size_t size) { for (size_t i = 0; i < size; i++) { result[i] = a[i] + b[i]; } }字符串处理 size_t strlen_custom(const char *restrict str) { size_t len = 0; while (*str++) len++; return len; }优化效果:循环展开 void process(int *restrict data, int n) { // 编译器可以安全地展开循环 for (int i = 0; i < n; i++) { data[i] *= 2; } }向量化 void scale_array(double *restrict arr, double factor, int n) { for (int i = 0; i < n; i++) { arr[i] *= factor; } // 编译器可以使用 SIMD 指令 }缓存优化 void matrix_multiply(double *restrict result, const double *restrict a, const double *restrict b, int rows, int cols, int k) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { result[i * cols + j] = 0; for (int p = 0; p < k; p++) { result[i * cols + j] += a[i * k + p] * b[p * cols + j]; } } } }注意事项:未定义行为 void dangerous(int *restrict a, int *restrict b) { *a = 10; *b = 20; // 如果 a 和 b 指向同一位置,行为未定义 }参数传递 void function(int *restrict p) { // p 在函数内部不会产生别名 } int main() { int x = 10; function(&x); // 安全 }结构体指针 struct Point { int x, y; }; void transform(struct Point *restrict p) { p->x *= 2; p->y *= 2; }实际应用示例:图像处理 void grayscale_image(unsigned char *restrict pixels, int width, int height) { for (int i = 0; i < width * height * 3; i += 3) { unsigned char gray = (pixels[i] + pixels[i+1] + pixels[i+2]) / 3; pixels[i] = pixels[i+1] = pixels[i+2] = gray; } }信号处理 void apply_filter(double *restrict output, const double *restrict input, const double *restrict kernel, int size, int kernel_size) { for (int i = 0; i < size; i++) { output[i] = 0; for (int j = 0; j < kernel_size; j++) { if (i + j < size) { output[i] += input[i + j] * kernel[j]; } } } }数据压缩 void compress_data(const int *restrict input, int *restrict output, int size) { int out_index = 0; int current = input[0]; int count = 1; for (int i = 1; i < size; i++) { if (input[i] == current) { count++; } else { output[out_index++] = current; output[out_index++] = count; current = input[i]; count = 1; } } }性能对比:无 restrict void add_slow(int *a, int *b, int *c, int n) { for (int i = 0; i < n; i++) { a[i] = b[i] + c[i]; } // 编译器必须考虑指针重叠 }有 restrict void add_fast(int *restrict a, const int *restrict b, const int *restrict c, int n) { for (int i = 0; i < n; i++) { a[i] = b[i] + c[i]; } // 编译器可以激进优化 }
阅读 0·2月18日 17:21

C语言中inline关键字的作用和使用限制是什么?

C语言中inline关键字的作用和使用限制是什么?inline 关键字基本概念:内联函数定义 inline int add(int a, int b) { return a + b; } int main() { int result = add(3, 5); // 编译器可能将函数调用展开为: result = 3 + 5; }内联的优势 // 消除函数调用开销 inline int square(int x) { return x * x; } // 使用 int y = square(10); // 可能展开为: int y = 10 * 10;使用场景:小型频繁调用的函数 inline int max(int a, int b) { return a > b ? a : b; } inline int min(int a, int b) { return a < b ? a : b; }访问器函数 struct Point { int x, y; }; inline int get_x(const struct Point *p) { return p->x; } inline void set_x(struct Point *p, int value) { p->x = value; }数学运算 inline double degrees_to_radians(double degrees) { return degrees * 3.14159265358979323846 / 180.0; } inline double radians_to_degrees(double radians) { return radians * 180.0 / 3.14159265358979323846; }使用限制:函数定义 // 头文件中 inline int add(int a, int b) { return a + b; } // 源文件中 extern inline int add(int a, int b);递归函数 // 递归函数不能完全内联 inline int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1); }复杂函数 // 复杂函数可能不会被内联 inline void complex_function(int *data, int size) { for (int i = 0; i < size; i++) { data[i] = perform_complex_calculation(data[i]); } }最佳实践:头文件定义 // math_utils.h #ifndef MATH_UTILS_H #define MATH_UTILS_H static inline int abs(int x) { return x < 0 ? -x : x; } static inline int clamp(int value, int min, int max) { return value < min ? min : (value > max ? max : value); } #endif条件内联 #ifdef ALWAYS_INLINE #define INLINE __attribute__((always_inline)) inline #else #define INLINE inline #endif INLINE int fast_function(int x) { return x * 2; }编译器提示 // GCC/Clang inline __attribute__((always_inline)) int always_inline(int x) { return x * 2; } // MSVC __forceinline int force_inline(int x) { return x * 2; }性能考虑:代码膨胀 // 过度内联可能导致代码膨胀 inline int small_func(int x) { return x + 1; } // 如果在多个地方调用,会生成多份代码缓存影响 // 内联可能改善指令缓存 inline int fast_operation(int x) { return (x << 1) + (x << 3); // x * 10 }编译器决策 // 编译器可能忽略 inline 建议 inline int maybe_inlined(int x) { return x * x; } // 编译器根据优化级别决定是否内联实际应用示例:容器操作 struct Vector { int *data; size_t size; size_t capacity; }; static inline int vector_get(const struct Vector *v, size_t index) { return v->data[index]; } static inline void vector_set(struct Vector *v, size_t index, int value) { v->data[index] = value; }位操作 static inline int set_bit(int value, int bit) { return value | (1 << bit); } static inline int clear_bit(int value, int bit) { return value & ~(1 << bit); } static inline int toggle_bit(int value, int bit) { return value ^ (1 << bit); }字符串操作 static inline int string_equals(const char *a, const char *b) { return strcmp(a, b) == 0; } static inline int string_length(const char *str) { return strlen(str); }注意事项:链接规则 // 头文件中定义 inline int func(int x) { return x * 2; } // 多个文件包含头文件时,每个文件都有自己的定义调试困难 // 内联函数在调试时可能难以跟踪 inline int debug_func(int x) { return x + 1; }优化级别 // 不同优化级别下,inline 效果不同 // -O0: 可能不内联 // -O2, -O3: 更可能内联
阅读 0·2月18日 17:20

C语言中extern关键字的作用和链接机制是什么?

C语言中extern关键字的作用和链接机制是什么?extern 关键字基本概念:声明外部变量 // file1.c int global_var = 100; // file2.c extern int global_var; // 声明,不分配内存 void function() { global_var = 200; // 访问 file1.c 中的变量 }声明外部函数 // file1.c int add(int a, int b) { return a + b; } // file2.c extern int add(int a, int b); // 可省略 extern void use_add() { int result = add(3, 5); }链接机制:内部链接 vs 外部链接 // 内部链接(static) static int internal_var = 10; static void internal_func() {} // 外部链接(默认) int external_var = 20; void external_func() {} // 显式外部链接 extern int explicit_var = 30; extern void explicit_func() {}跨文件共享 // config.h extern int MAX_CONNECTIONS; extern const char* LOG_FILE; // config.c int MAX_CONNECTIONS = 100; const char* LOG_FILE = "app.log"; // main.c #include "config.h" int main() { printf("Max connections: %d\n", MAX_CONNECTIONS); }使用场景:头文件声明 // mylib.h #ifndef MYLIB_H #define MYLIB_H extern int library_version; extern void library_init(); extern void library_cleanup(); #endif避免重复定义 // common.h extern int shared_counter; // file1.c #include "common.h" int shared_counter = 0; // 定义 // file2.c #include "common.h" // 只声明,不定义条件编译 // platform.h #ifdef _WIN32 extern void windows_specific(); #elif defined(__linux__) extern void linux_specific(); #endif注意事项:声明 vs 定义 // 声明(不分配内存) extern int var1; // 定义(分配内存) int var1 = 10; extern int var2 = 20; // 也是定义const 变量的 extern // 默认情况下 const 变量是内部链接 const int CONSTANT = 100; // 需要显式声明为外部链接 extern const int EXTERN_CONSTANT = 200;初始化 // 正确 extern int var; // 声明 int var = 10; // 定义 // 错误 extern int var = 10; // 虽然合法,但不推荐高级应用:动态链接库 // mylib.c __declspec(dllexport) int lib_function(int x) { return x * 2; } // main.c __declspec(dllimport) int lib_function(int x);内联函数 // header.h static inline int max(int a, int b) { return a > b ? a : b; }宏与 extern 结合 // api.h #ifdef API_EXPORTS #define API __declspec(dllexport) #else #define API __declspec(dllimport) #endif API void api_function();最佳实践:头文件组织 // module.h #ifndef MODULE_H #define MODULE_H #ifdef __cplusplus extern "C" { #endif extern int module_init(); extern void module_cleanup(); #ifdef __cplusplus } #endif #endif避免全局变量 // 不推荐 extern int global_state; // 推荐:使用访问函数 int get_state(); void set_state(int value);命名空间模拟 // network.h extern int network_init(); extern void network_send(const char* data); // file.h extern int file_open(const char* path); extern void file_write(int fd, const char* data);常见错误:重复定义 // file1.c int shared_var = 10; // file2.c int shared_var = 20; // 链接错误:重复定义未定义引用 // file1.c extern int undefined_var; void function() { int x = undefined_var; // 链接错误:未定义引用 }类型不匹配 // file1.c int value = 10; // file2.c extern double value; // 链接错误:类型不匹配
阅读 0·2月18日 17:20

C语言中静态(static)关键字的作用域和生命周期是什么?

C语言中静态(static)关键字的作用域和生命周期是什么?static 关键字的三种用法:静态局部变量 void counter() { static int count = 0; // 只初始化一次 count++; printf("Count: %d\n", count); } int main() { counter(); // Count: 1 counter(); // Count: 2 counter(); // Count: 3 }静态全局变量 static int global_var = 100; // 文件作用域 void function() { global_var++; } // 其他文件无法访问 global_var静态函数 static void helper_function() { printf("This is a static function\n"); } // 只能在当前文件中调用作用域和生命周期:静态局部变量 void example() { // 作用域:函数内部 // 生命周期:整个程序运行期间 static int value = 10; // 每次调用都保留上次的值 value++; }静态全局变量 // file1.c static int file_global = 50; // file2.c extern int file_global; // 链接错误静态函数 // file1.c static int internal_calculation(int x) { return x * 2; } // file2.c int internal_calculation(int x); // 链接错误实际应用场景:单例模式 int* get_instance() { static int *instance = NULL; if (instance == NULL) { instance = malloc(sizeof(int)); *instance = 0; } return instance; }缓存机制 int expensive_calculation(int n) { static int cache[100] = {0}; if (n < 100 && cache[n] != 0) { return cache[n]; } int result = /* 复杂计算 */; if (n < 100) { cache[n] = result; } return result; }计数器 int get_unique_id() { static int next_id = 0; return next_id++; }状态保持 void state_machine() { static enum { INIT, RUNNING, DONE } state = INIT; switch (state) { case INIT: printf("Initializing...\n"); state = RUNNING; break; case RUNNING: printf("Running...\n"); state = DONE; break; case DONE: printf("Done!\n"); break; } }与 const 的区别:static vs const // static: 控制作用域和生命周期 static int value = 10; // const: 控制可修改性 const int value = 10; // 可以组合使用 static const int CONSTANT = 100;线程安全考虑:非线程安全的静态变量 int* get_instance_unsafe() { static int *instance = NULL; // 非线程安全 if (instance == NULL) { instance = malloc(sizeof(int)); } return instance; }线程安全的静态变量 #include <pthread.h> int* get_instance_safe() { static int *instance = NULL; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mutex); if (instance == NULL) { instance = malloc(sizeof(int)); } pthread_mutex_unlock(&mutex); return instance; }最佳实践:信息隐藏 // module.c static int internal_state = 0; static void internal_helper() { internal_state++; } void public_interface() { internal_helper(); }避免全局变量污染 // 使用 static 限制作用域 static int module_config = 0; void set_config(int value) { module_config = value; }初始化顺序 void function() { static int initialized = 0; static int cache[100]; if (!initialized) { for (int i = 0; i < 100; i++) { cache[i] = i * i; } initialized = 1; } return cache[10]; }
阅读 0·2月18日 17:18

C语言中可变参数函数的实现原理和使用方法是什么?

C语言中可变参数函数的实现原理和使用方法是什么?可变参数函数基础:基本定义 #include <stdarg.h> int sum(int count, ...) { va_list args; va_start(args, count); int total = 0; for (int i = 0; i < count; i++) { total += va_arg(args, int); } va_end(args); return total; } int result = sum(3, 10, 20, 30);核心宏 va_list args; // 声明参数列表 va_start(args, last); // 初始化参数列表 va_arg(args, type); // 获取下一个参数 va_end(args); // 清理参数列表典型应用场景:格式化输出 void debug_print(const char *format, ...) { va_list args; va_start(args, format); #ifdef DEBUG vprintf(format, args); #endif va_end(args); } debug_print("Value: %d, String: %s\n", 42, "Hello");自定义错误处理 void error_handler(int code, const char *format, ...) { va_list args; va_start(args, format); fprintf(stderr, "Error %d: ", code); vfprintf(stderr, format, args); fprintf(stderr, "\n"); va_end(args); } error_handler(404, "File %s not found", "config.txt");字符串构建 char* string_build(const char *format, ...) { va_list args; va_start(args, format); int size = vsnprintf(NULL, 0, format, args); va_end(args); char *buffer = malloc(size + 1); if (buffer) { va_start(args, format); vsnprintf(buffer, size + 1, format, args); va_end(args); } return buffer; }高级用法:类型安全检查 void safe_printf(const char *format, ...) { va_list args; va_start(args, format); const char *p = format; while (*p) { if (*p == '%') { p++; switch (*p) { case 'd': va_arg(args, int); break; case 'f': va_arg(args, double); break; case 's': va_arg(args, char*); break; } } p++; } va_end(args); }可变参数计数 int count_args(int first, ...) { if (first == -1) return 0; va_list args; va_start(args, first); int count = 1; int value; while ((value = va_arg(args, int)) != -1) { count++; } va_end(args); return count; }传递可变参数 void wrapper_printf(const char *format, ...) { va_list args; va_start(args, format); vprintf(format, args); va_end(args); }注意事项:参数类型匹配 // 危险:类型不匹配 void example(const char *format, ...) { va_list args; va_start(args, format); int i = va_arg(args, int); // 必须与实际参数类型匹配 double d = va_arg(args, double); va_end(args); }默认参数提升 void promoted_args(...) { va_list args; va_start(args, 0); // char 和 short 会提升为 int // float 会提升为 double int i = va_arg(args, int); double d = va_arg(args, double); va_end(args); }内存管理 void process_strings(...) { va_list args; va_start(args, 0); char *str; while ((str = va_arg(args, char*)) != NULL) { // 处理字符串 // 注意:不释放字符串 } va_end(args); }实际应用示例:日志系统 typedef enum { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR } LogLevel; void log_message(LogLevel level, const char *format, ...) { const char *level_str[] = {"DEBUG", "INFO", "WARN", "ERROR"}; printf("[%s] ", level_str[level]); va_list args; va_start(args, format); vprintf(format, args); va_end(args); printf("\n"); }配置解析 void parse_config(const char *key, ...) { va_list args; va_start(args, key); void *ptr; while ((ptr = va_arg(args, void*)) != NULL) { // 解析配置并存储到指针 } va_end(args); } int port, timeout; parse_config("server", &port, &timeout, NULL);数组求和 double sum_array(int count, ...) { va_list args; va_start(args, count); double sum = 0.0; for (int i = 0; i < count; i++) { sum += va_arg(args, double); } va_end(args); return sum; } double result = sum_array(3, 1.5, 2.5, 3.5);
阅读 0·2月18日 17:17