2013-06-19 26 views
5

我写了一个printf myselef使用va_list/va_arg/va_start/va_end/va_arg。使用gcc编译一个项目,显示“未定义的引用中止”

typedef char *va_list; 
#define _AUPBND    (sizeof (acpi_native_int) - 1) 
#define _ADNBND    (sizeof (acpi_native_int) - 1) 
#define _bnd(X, bnd)   (((sizeof (X)) + (bnd)) & (~(bnd))) 
#define va_arg(ap, T)   (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) 
#define va_end(ap)    (void) 0 
#define va_start(ap, A)   (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND)))) 

起初,我从Linux内核复制这些宏和printf的能打印的32位整数正确的,但不能打印的64位整数,并打印双/浮动可能失败或collapse.Then我检查代码和我猜va_ *可能有错误,所以我使用__builtin_va_ *而不是内核的va_ *。

typedef __builtin_va_list va_list; 
#define va_start(v,l) __builtin_va_start(v,l) 
#define va_end(v)  __builtin_va_end(v) 
#define va_arg(v,l)  __builtin_va_arg(v,l) 

但是GCC提示“未定义的引用'中止'”,所以我写了一个空中止()和myprintf工作corretly。 我的问题是:

  1. 为什么linux内核的va_list/va_arg/va_start/va_end/va_arg不能用于printf 64位整数和双/浮动?
  2. 当我用__builtin_va_start/__builtin_va_arg/__builtin_va_end/__builtin_va_list,为什么GCC提示“未定义参考abort'"? But I can not find the definition of __builtin_va_ *`,他们哪儿定义?
+2

怎么样?另外'_bnd'(_bnd被假定为_va_align)在其中定义不同:'#define __va_align(ty)((sizeof(ty)+ sizeof(int) - 1)&〜(sizeof(int) - 1)) ' – 2013-06-19 11:28:23

+0

同意@Armin;你为什么不只是使用va_arg标准的标题? –

+0

@Oli Charlesworth事实上,我们的项目没有os支持,我们无法控制打印的位置,所以stdio.h不符合我们的要求。 – Ezio

回答

0

不要削减,并从Linux头贴的东西,而是把这个在源文件的顶部:

#include <stdarg.h> 

这会给你你才能使用va_listva_arg需要的一切然而,不会拉在printf或任何标准的I/O塞入。 f(居住在<stdio.h>)。

1

gcc的__builtin_va_arg()显然会调用abort()(至少在某些平台上或情况),如果它有一个类型参数调用不能有在函数调用的参数列表的...部分已经过去了。

例如,由于促销一个charfloat作为这样的参数传递将已被晋升为intdouble。访问这些参数为va_arg(ap,char)va_arg(ap,float)是未定义的行为,gcc可能会在这种情况下调用abort() - 或者它可能会做其他事情(我的MinGW编译器将执行一条无效指令以导致崩溃)。

编译时,您可能会看到这样的事情:

In file included from D:\temp\test.c:2:0: 
D:\temp\test.c: In function 'foo': 
D:\temp\test.c:12:16: warning: 'char' is promoted to 'int' when passed through '...' [enabled by default] 
    c = va_arg(ap,char); 
       ^
D:\temp\test.c:12:16: note: (so you should pass 'int' not 'char' to 'va_arg') 
D:\temp\test.c:12:16: note: if this code is reached, the program will abort 

__builtin_va_*的“定义”被编译成编译器(这就是为什么“内置”是名称的一部分)。

就可变参数访问的Linux宏而言:尽管您从linux内核头获取的定义确实存在于include/acpi/platform/acenv.h中,但如果仔细查看有效的条件编译,在构建Linux内核时会发现这些宏没有被使用。我不确定这些宏是什么时候生效的,但是它们不能用于x64/x86-64/amd64构建,因为该平台上的ABI并不完全基于堆栈。有关详细信息,请参见“System V应用程序二进制接口 - AMD64体系结构处理器补充”的第3.5.6节。

相关问题