c语言宏定义实现多个数的排序

本文介绍了C语言中使用三目运算符和typeof关键字来求取变量的最大值,并展示了如何通过宏定义实现多个整数之间的最大值计算。示例代码包括了从两个到四个整数的最大值宏定义,并给出了实际运行的输出结果。此外,还探讨了使用括号和typeof确保宏定义的正确性,以及如何实现多个任意类型数值的最大值。

基础概念

1.三目运算符: ?:

int max;
max = 6 > 5 ? 3:2;

这条代码的意思是 6是否大于5,如果是,则结果为真,max = 3,如果不是,则结果为假,max = 2。

2 获取变量的类型: typeof

char a;
int size;
typeof (a) _a = a;//等价于 char _a = a;
size = sizeof(typeof(_a));//等价于 size = sizeof(char);

typeof (a) _a = a 等价于 char _a = a。
size = sizeof(typeof(_a));
这条代码的意思是用typeof 获取 _a的存储类型char, size = sizeof(char),size为1(char 占一个字节)。

宏定义实现多个整形数的最大值

1.宏定义实现2个整形数的最大值

#define MAX_2(a,b) ((a) >= (b) ? (a):(b))

2.宏定义实现3个整形数的最大值

#define MAX_3(a,b,c) ((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? (a):(b))):(c))

3.宏定义实现4个整形数的最大值

#define MAX_4(a,b,c,d) ((((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? \
(a):(b))):(c))) >= (d)  ? (((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? \
(a):(b))):(c))):(d))

4.运算结果

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_2(a,b) ((a) >= (b) ? (a):(b))

#define MAX_3(a,b,c) ((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? (a):(b))):(c))

#define MAX_4(a,b,c,d) ((((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? \
(a):(b))):(c))) >= (d) ? (((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? \
(a):(b))):(c))):(d))

void main(void)
{
    printf("max_2:%d\n",MAX_2(1,99));
    printf("max_3:%d\n",MAX_3(1111,99,188));
    printf("max_4:%d\n",MAX_4(11,199,188,1));
}
输出结果
liu@ubuntu:~/code_test/c_test$ ./a.out 
max_2:99
max_3:1111
max_4:199
liu@ubuntu:~/code_test/c_test$ 

5.替换法快速实现多个数值的最大值

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_2(a,b) ((a) >= (b) ? (a):(b))
#define MAX_3(a,b,c) ((MAX_2(a,b)) >= (c) ? (MAX_2(a,b)):(c))
#define MAX_4(a,b,c,d) ((MAX_3(a,b,c)) >= (d) ? (MAX_3(a,b,c)):(d))
#define MAX_5(a,b,c,d,e) ((MAX_4(a,b,c,d)) >= (e) ? (MAX_4(a,b,c,d)):(e))

// #define MAX_3(a,b,c) ((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? (a):(b))):(c))


// #define MAX_4(a,b,c,d) ((((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? \
// (a):(b))):(c))) >= (d) ? (((((a) >= (b) ? (a):(b))) >= (c) ? (((a) >= (b) ? \
// (a):(b))):(c))):(d))

void main(void)
{
    printf("max_2:%d\n",MAX_2(1,99));
    printf("max_3:%d\n",MAX_3(1111,99,188));
    printf("max_4:%d\n",MAX_4(11,199,188,1));
    printf("max_5:%d\n",MAX_5(11,199,2000,188,15555));
}
输出结果
liu@ubuntu:~/code_test/c_test$ ./a.out 
max_2:99
max_3:1111
max_4:199
max_5:15555
liu@ubuntu:~/code_test/c_test$ 

6.多个任意类型数值的最大值或最小值

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_2(a,b) ({\
                        typeof(a) _a = a;\
                        typeof(b) _b = b;\
                        (_a) >= (_b) ? (_a):(_b);\
                    })

#define MAX_3(a,b,c) ({typeof(c) _c = c;(MAX_2(a,b)) >= (_c) ? (MAX_2(a,b)):(_c);})
#define MAX_4(a,b,c,d) ({typeof(d) _d = d;(MAX_3(a,b,c)) >= (_d) ? (MAX_3(a,b,c)):(_d);})
#define MAX_5(a,b,c,d,e) ({ typeof(e) _e = e;(MAX_4(a,b,c,d)) >= (_e) ? (MAX_4(a,b,c,d)):(_e);})

void main(void)
{
    char a;
    int b;
    int a_size;
    int b_size;

    a_size = sizeof(typeof(a));

    typeof (b) _a = b;
    b_size = sizeof(typeof(_a));
       
    printf("a_size:%d\n",a_size);
    printf("b_size:%d\n",b_size);

    printf("max_2:%d\n",MAX_2(1,99));
    printf("max_3:%d\n",MAX_3(1111,99,188));
    printf("max_4:%d\n",MAX_4(11,199,188,1));
    printf("max_5:%d\n",MAX_5(11,199,2000,188,15555));
}

输出结果
liu@ubuntu:~/code_test/c_test$ gcc define.c 
liu@ubuntu:~/code_test/c_test$ ./a.out 
a_size:1
b_size:4
max_2:99
max_3:1111
max_4:199
max_5:15555
liu@ubuntu:~/code_test/c_test$ 
<think>嗯,用户这次问的是C语言中offsetof的具体作用,而且引用了段站内资料。从提问方式和引用内容看,用户应该是有一定C语言基础的程序员,可能正在学习底层实现或阅读开源代码时遇到了这个。 用户引用的资料很全面,包括的分解步骤、原理解析、标准库实现示例甚至内存对齐问题。不过用户特别标注了“上述引用仅供参考”,说明ta更希望得到系统性的原理解释,而不是碎片化的引用堆砌。 注意到用户上次提问是关于快速排序的底层实现,这次转向C语言,可能是在学习系统编程或准备面试。这类问题通常需要结合内存布局来理解,所以我决定从四个层次展开: 1. 的语法分解(对应引用1和2的步骤拆解) 2. 利用空指针访问的原理(重点解释0地址转换这个技巧) 3. 偏移量的本质(关联引用4提到的对齐问题) 4. 实际应用场景(结合container_of) 特别需要澄清的是(char*)转换的必要性。引用2提到可以省略,但实际在ANSI C中必须保留,因为void*指针算术运算在早期标准未定义,这点必须明确说明。 用户给出的示例代码显示packed结构体的偏移量差异,这个典型案例应该保留。不过TypeA和TypeB的定义重复了,需要优化展示方式。考虑到用户可能测试代码,输出结果用注释形式呈现更直观。 安全方面要强调:虽然(TYPE*)0是未定义行为,但主流编译器都支持这种特殊用法。如果用户关注可移植性,可以后续讨论__builtin_offsetof。 相关问题设计要递进:从宏定义原理(问题1)到实际应用(问题3),再到进阶的内存对齐(问题4),最后是编译器差异(问题5)。这样既覆盖基础,又给深入学习的路径。 </think>`offsetof(TYPE, MEMBER)` 是 **用于计算结构体(`TYPE`)中指定成员(`MEMBER`)相对于结构体起始地址的偏移量(以字节为单位)** 的关键工具。其原理和步骤如下: --- ### **宏定义解析** ```c #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) ``` #### **逐步拆解原理** 1. **`(TYPE *)0`** 将值 `0` 强制转换为指向 `TYPE` 类型的指针。这意味着创建一个指向地址 `0` 的虚拟结构体指针(**不进行实际内存分配**)。 2. **`((TYPE *)0)->MEMBER`** 通过虚拟指针访问结构体的成员 `MEMBER`。此时编译器会计算 `MEMBER` 在结构体中的相对位置(偏移量)。 3. **`&((TYPE *)0)->MEMBER)`** 取成员 `MEMBER` 的地址。由于结构体首地址为 `0`,因此 `MEMBER` 的地址值 **等于其偏移量**(例如,若偏移量为 4 字节,则地址为 `0x4`)。 4. **`(size_t)` 类型转换** 将偏移量值转换为 `size_t` 类型(无符号整),确保结果可跨平台使用。 --- ### **核心作用** - **获取成员偏移量**: 直接输出成员在结构体中的位置(字节),不受结构体实例影响。 - **避免未定义行为**: 虽然对 `0` 地址解引用理论上未定义,但所有主流编译器(GCC、Clang 等)均支持此用法,且标准库(如 `<stddef.h>`)依赖此实现[^2][^3]。 --- ### **示例说明** ```c #include <stddef.h> #include <stdio.h> typedef struct { char a; // 1 字节 int b; // 通常占 4 字节(对齐后) double c; // 通常占 8 字节 } MyStruct; int main() { size_t off_b = offsetof(MyStruct, b); size_t off_c = offsetof(MyStruct, c); printf("Offset of b: %zu\n", off_b); // 输出 4(1 字节 char + 3 字节填充对齐) printf("Offset of c: %zu\n", off_c); // 输出 8(4 字节 int + 对齐后位置) return 0; } ``` **输出**: ``` Offset of b: 4 Offset of c: 8 ``` --- ### **关键知识点** 1. **内存对齐影响**: 偏移量由编译器根据成员类型和平台对齐规则自动计算(如 `int` 通常需 4 字节对齐)[^4]。 2. **实际应用场景**: - **底层据结构**(如链表、内核开发中 `container_of` ); - **序列化/反序列化**(根据偏移量读写二进制据)[^5]; - **调试内存布局**。 --- ### **注意事项** - **不可直接解引用 `0` 地址**: 利用编译器计算偏移量,实际运行时访问 `0` 地址会引发段错误。 - **标准库实现**: 现代编译器常用内建函 `__builtin_offsetof` 优化该[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值