不定参数在C语言中的应用实例

[09-12 18:30:04]   来源:http://www.88dzw.com  EDA/PLD   阅读:8780

文章摘要:#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )其中_INTSIZEOF(n)计算比n大的sizeof(int)的最小倍数,如果n=101,则_INTSIZEOF(n)为104.va_start执行完毕后,ap指向变量v后第一个4字节对齐的地址。例如,v的地址为0x123456, v的大小为13,则v后面的下一个与字边界对齐的地址为0x123456+0x0D=0x123463再调整为与4字节对齐的下一个地址,也就是0x123464.va_arg函数定义为:#define va_arg(ap,t) ( *(t *)((ap +

不定参数在C语言中的应用实例,标签:eda技术,eda技术实用教程,http://www.88dzw.com

  #define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )

  其中_INTSIZEOF(n)计算比n大的sizeof(int)的最小倍数,如果n=101,则_INTSIZEOF(n)为104.

  va_start执行完毕后,ap指向变量v后第一个4字节对齐的地址。例如,v的地址为0x123456, v的大小为13,则v后面的下一个与字边界对齐的地址为0x123456+0x0D=0x123463再调整为与4字节对齐的下一个地址,也就是0x123464.

  va_arg函数定义为:

  #define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

  分析与va_start一样,它的结果是使ap指向当前变量的下一个变量。

  这样,我们只要在开始时使用va_start把不定参数列表赋值给ap,然后依次用va_arg获得不同参数即可。

  潜在问题

  使用不定参数列表,有两个问题特别需要注意。

  问题1的理解相对简单:我们在重载一个函数的时候,不能依赖不定参数列表部分对函数进行区分。

  假定我们定义两个重载函数如下:

  int func(int a, int b, ……)

  int func(int a, int b, float c);

  则上述函数会导致编译器不知道怎么去解释func(1,2, 3.3),因为当第三个参数为浮点数时,两个实现都可以满足匹配要求。一般情况,个人建议对于不定参数函数不要去做重载。

  另外一个问题是关于类型问题。绝大多数情况下,C和C++的变量都是强类型的,而不定参数列表属于一个特例。

  当我们调用va_arg的时候,我们指明下一个参数的类型,而在执行的时候,va_arg正是根据这个信息在堆栈上来找到对应的参数的。如果我们需要的类型和真实传递进来的参数完全一致时自然没有问题,但是假如类型不一样,则会有大麻烦。

  假如上面的的sumi函数,我们用下面方法调用:

  int sum = sumi(1, 2.2, 3, 0)

  注意第二个参数我们传入了一个double类型的2.2,我们希望sumi在做加法时可以做隐式类型转换,转换为int进行计算。但是实际情况时,当我们分析到这个参数时,调用的是:

  c=va_arg(ap,int)

  据前文va_arg的定义,这个宏被翻译成:

  #define va_arg(ap,t)    ( *(int *)((ap += _INTSIZEOF(int)) - _INTSIZEOF(int)) )

  如果后面的+=计算出正确的地址,最后就变成

  *(int*)addr

  如果希望能得到正确的整数值,必须要求addr所在的地址是一个真实的int类型。但是当我们传入double时,实际上其内存布局和int完全不同,因此我们得不到需要的整数。感兴趣的朋友可以用下面简单的代码做测试:

  double a;

  a=1.1;

  int b = *(int*) & a;

  因此,当我们调用有不定参数列表的函数时,不要期望系统做隐式类型转换,系统不会做这种检查或者转换,你给的参数类型必须严格和你希望的值一样。


上一页  [1] [2] 


Tag:EDA/PLDeda技术,eda技术实用教程EDA/PLD

《不定参数在C语言中的应用实例》相关文章

分类导航
最新更新
热门排行