va_list和va_start和((A*)0)->a

本文详细解释了C语言中可变参数函数的工作原理,包括va_list、va_start、va_arg及va_end的使用方法。并通过示例展示了如何计算参数地址和大小,确保参数指针的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C语言函数是从右到左入栈的

va_list ap;//=char *ap;(一个字符指针)

va_start(ap,v) 中 ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )//返回参数v后的参数列表地址(V地址+V的长度)

va_arg(ag,type):va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )//取指定类型的值int i=va_arg(ap,int),并且使ap指向向一个参数

va_end(ag):清空参数列表,并置参数指针ag无效。说明:指针ag被置无效后,可以通过调用 va_start()、va_arg恢复arg。每次调用va_start() / va_arg()后,必须得有相应的va_end()与之匹配。参数指针可以在参数列表中随意地来回移动,但必须在va_start() … va_end()之内

注:

其中:#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) – 1) & ~(sizeof(int) – 1)

~是位取反的意思。_INTSIZEOF(n)整个做的事情就是将n的长度化为int长度的整数倍。

比如n为5,二进制就是101b,int长度为4,二进制为100b,那么n化为int长度的整数倍就应该为8。((5+4-1)/4)*4=8;

~(sizeof(int) – 1) )就应该为~(4-1)=~(00000011b)=11111100b,这样任何数& ~(sizeof(int) – 1) )后最后两位肯定为0,就肯定是4的整数倍了。

(sizeof(n) + sizeof(int) – 1)就是将大于4m但小于等于4(m+1)的数提高到大于等于4(m+1)但小于4(m+2),这样再& ~(sizeof(int) – 1) )后就正好将原长度补齐到4的倍数了 

即:

((5+4-1)/4)

(sizeof(n) + sizeof(int) – 1)&~(sizeof(int-1)

 

  栈底 高地址 
    | .......      
    | 函数返回地址 
    | .......       
    | 函数最后一个参数 
    | ....                        
    | 函数第一个可变参数       <--va_start后ap指向  
    | 函数最后一个固定参数 
    | 函数第一个固定参数  
    栈顶 低地址 

 Linux内核中,用两个非常巧妙地宏实现了,一个是offsetof宏,另一个是container_of宏,下面讲解一下这两个宏。

1.  offsetof宏
【定义】:#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )
【功能】: 获得一个结构体变量成员在此结构体中的偏移量。
【例子】:
struct A
{
    int x ;
    int y;
    int z;
};
 
void main()
{
    printf("the offset of z is %d",offsetof( struct A, z )  );
}
 
// 输出结果为 8
【分析】:
 
该宏,TYPE为结构体类型,MEMBER 为结构体内的变量名。
 
(TYPE *)0) 是欺骗编译器说有一个指向结构TYPE 的指针,其地址值0
 
(TYPE *)0)->MEMBER 是要取得结构体TYPE中成员变量MEMBER的地址. 因为基址为0,所以,这时MEMBER的地址当然就是MEMBER在TYPE中的偏移了

转载于:https://www.cnblogs.com/fujinliang/archive/2012/11/24/2785348.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值