GVKun编程网logo

c – 如何在GCC上创建va_list?(gcc创建c文件)

31

在这篇文章中,我们将带领您了解c–如何在GCC上创建va_list?的全貌,包括gcc创建c文件的相关情况。同时,我们还将为您介绍有关android–如何在主屏幕上创建VPN连接快捷方式?、c–如何实

在这篇文章中,我们将带领您了解c – 如何在GCC上创建va_list?的全貌,包括gcc创建c文件的相关情况。同时,我们还将为您介绍有关android – 如何在主屏幕上创建VPN连接快捷方式?、c – 如何实施“__builtin_va_list”?、c – 重用va_list、c函数中传递可变参数:va_list,va_start,va_arg,va_end的知识,以帮助您更好地理解这个主题。

本文目录一览:

c – 如何在GCC上创建va_list?(gcc创建c文件)

c – 如何在GCC上创建va_list?(gcc创建c文件)

我正在尝试转换一些代码,以便它也在 gcc上编译(现在,它仅在MSVC上编译).

我坚持的代码是伪格式化函数,它接受一个格式字符串和零个或多个参数(const char * format,…)作为输入.然后它将处理一些占用一些参数的占位符,并将其余的传递给vsprintf以及动态生成的新va_list.

这是生成新va_list的实际代码:

char *new_args = (char *) malloc(sum);
char *n = new_args;

for(int i = 0; i < nArgs; i++)
{
    int j   = order[i];
    int len = _getlen(types[j]);

    memcpy(n,args + cumulOffsets[j],len);
    n += len;
}

vsprintf(buffer,sFormat.c_str(),new_args);

在我的辩护中,我没有,也绝不会写这段代码.事实上,我认为这是我一生中见过的最讨厌的事情之一.

但是,这个功能非常复杂,非常陈旧,非常重要.它也没有被修改多年(好吧,除了现在),所以虽然我想从头开始重写它,但我无法证明它需要的时间加上它会引入的错误.

所以,我需要一种方法在GCC上做同样的事情..但是有一个va_list不是char *所以我得到:

error: ISO C++ forbids casting to an array type '__va_list_tag [1]'

解决方法

我有点迷茫.为什么需要一个新的动态生成的va_list?为什么不重用旧的呢?

我相信vsnprintf()使用当前的va_list对象(如果你可以调用它).所以你可以自由地使用va_start(),通过va_arg()使用你想要的参数,然后通过va_list将剩下的参数传递给vsnprintf(),然后调用va_end().

我错过了什么吗?为什么深拷贝?

如果你确实需要深层复制,为什么不刷新va_start(),通过va_arg()删除你想要的参数,然后将生成的va_list对象传递给vsnprintf().

(每次调用va_arg都会修改va_list对象,以便下一个调用返回下一个参数.)

或者,您可以使用va_copy(). (尽管一定要用相应的va_end()跟随它.)

附录:另请注意,这些va_宏基于C89& C99标准. GNU g将支持它们.微软有点受限.

跟进TonyK的评论:

如果您从va_list中删除前N个项目,我上面所说的就可以了.如果你从中间拉出物品,那就更难了.

没有可移植的方法来构造va_list.

但是,您可以拆分格式字符串,使用它来确定对象类型(double,float,int等),并使用它自己的格式字符串(原始格式字符串的子部分)单独打印每个字符串.多个snprintf()调用将导致一些开销.但如果不经常调用这个例程,它应该是可行的.

您还可以使用适当制作的va_list打印出原始格式字符串的子部分.换句话说,第一个vsnprintf()调用打印元素1..3,第二个元素5..7,第三个10..13等等(因为vsnprintf()会忽略va_list上的额外元素超出它的需要你只需要一系列相应的格式字符串片段,并根据每个vsnprintf()调用的需要用va_arg()弹出va_list中的项目.)

android – 如何在主屏幕上创建VPN连接快捷方式?

android – 如何在主屏幕上创建VPN连接快捷方式?

我创建了一个虚拟专用网络连接 http://www.vpnbook.com,现在我只想在Android手机的主屏幕上创建虚拟专用网络连接的快捷方式.

是否可以在Android手机Google nexus 5的主屏幕上创建虚拟专用网络连接快捷方式?

解决方法

据我所知,Nexus 5上的Android 5.0.1版本没有任何可让您创建VPN配置文件快捷方式的小部件.但是,它有一个“设置”快捷方式1 x 1小部件,可让您创建VPN设置的快捷方式,每次您要连接到VPN网络时,您都可以节省几步.

如果您使用“设置”快捷方式,则可以将其添加到主屏幕:

1- Long tap an empty area on any Home screen.
2- Tap Widgets.
3- Find,tap and drag the Settings shortcut to your home screen.

4- Select VPN,and you’re done.

除了上面的答案,我还没有遇到任何可靠的第三方应用程序,让您创建VPN配置文件快捷方式.

如果您知道一种更好的方式,您可以创建VPN配置文件的快捷方式,请在注释中分享.

c – 如何实施“__builtin_va_list”?

c – 如何实施“__builtin_va_list”?

我想深入研究macOS上C语言中函数“printf”的实现. “printf”使用< stdarg.h>头文件.我打开< stdarg.h>文件并发现va_list只是一个宏.

那么,我真的好奇__builtin_va_list是如何实现的?我知道它是特定于编译器的.我在哪里可以找到__builtin_va_list的定义?我应该下载clang编译器的源代码吗?

解决方法

So,I am really curIoUs about how the __builtin_va_list is implemented?

__builtin_va_list在GCC编译器(或Clang/LLVM编译器)中实现.因此,您应该研究GCC编译器源代码以了解详细信息.

请看gcc/builtins.def& gcc/builtins.c更多.

我不熟悉Clang,它实现了相同的内置.

但是GCC和GCC都是Clang是开源或免费软件.它们是复杂的野兽(每行数百万行代码),因此您可能需要多年的工作才能理解它们.

请注意,编译器的ABI很重要.有关详细信息,请查看X86 psABI中的示例.

BTW,Grady Player评论说:

Pops the correct number of bytes off of the stack for each of those tokens…

不幸的是,今天它要复杂得多.在当前的处理器和ABI上,calling conventions确实使用processor registers来传递一些参数(而且细节中存在邪恶).

Should I download the source code of clang compiler?

是的,您还需要分配几年的工作来了解细节.

几年前,我确实编写了一些教程幻灯片和关于GCC实现的外部文档的链接,请参阅我的GCC MELT documentation页面(有点烂).

c – 重用va_list

c – 重用va_list

我需要通过va_list进行两次(或更多次)传递.我有一个大小的缓冲区,我想用sprintf写一个格式化的字符串.如果格式化的字符串不适合分配的空间,我想要将分配的空间加倍并重复直到它适合.

(作为旁注,我希望能够首先计算格式化字符串的长度并分配足够的空间,但我发现可以做到的唯一功能是_snprintf,并且在VS2005中不推荐使用…)

现在,到目前为止没有问题:我使用vsnprintf并在每次调用之前调用va_start.

但我还创建了一个函数,它将va_list作为参数,而不是“…”.然后我再也不能使用va_start了!我读过有关va_copy的内容,但VS2005不支持.

那么,你会怎么做?

解决方法

我看到没有可移植的方式(我认为va_copy已经在C99中引入,因为没有可移植的方法来实现其在c89中的结果). va_list可以是声明为的模拟引用类型
typedef struct __va_list va_list[1];

(请参阅gmp了解该技巧的另一个用户)并解释了围绕它们的许多语言限制.顺便说一下,如果可移植性很重要,请不要忘记va_end.

如果可移植性不重要,我会检查stdard.h,看看我是否可以考虑真正的声明来破解.

c函数中传递可变参数:va_list,va_start,va_arg,va_end

c函数中传递可变参数:va_list,va_start,va_arg,va_end

可变参数函数就是输入的参数个数是可变的

最经典的是printf和scanf,这两个函数的声明如下:

1 int printf(const char *format, ...);
2 int scanf(const char *format, ...);

这两个函数声明中省略号(...)表示任意个数的参数

函数的数据是存放于栈中的,那么给一个函数传递传递参数的过程就是将函数的参数从右向左逐次压栈,例如:

func(int i, char c, doube d)

这个函数传递参数的过程就是将d,c,i逐次压到函数的栈中,由于栈是从高地址向低地址扩展的,所以d的地址最高,i的地址最低。

典型的写法如下:

1 void func(char *fmt, ...){
2       va_list ap;
3       va_start(ap, fmt);
4       va_arg(ap, int);
5       va_end(va);      
6 }

  这里ap是一个指针,指向参数的地址。

  va_start()让ap指向函数的最后一个确定的参数(声明程序中是fmt)的地址。

  va_arg()根据ap指向的地址和第二个参数所确定的类型,将这个参数的中的数据提取出来,作为返回值,同时让ap指向下一个参数。

  va_end()让ap这个指针指向0。

 

关于这三个参数实现的宏可以参看下面的实现:

 

1 #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
2 #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址
3 #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数的值
4 #define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效

 

 

以下为编译PL0语言的SET.c源码中的createset()函数,在此函数中就是用了可变长参数:

 1 void setinsert(symset s, int elem)
 2 {
 3     snode* p = s;
 4     snode* q;
 5 
 6     while (p->next && p->next->elem < elem)
 7     {
 8         p = p->next;
 9     }
10     
11     q = (snode*) malloc(sizeof(snode));
12     q->elem = elem;
13     q->next = p->next;
14     p->next = q;
15 } // setinsert
16 
17 symset createset(int elem, .../* SYM_NULL */)
18 {
19     va_list list;
20     symset s;
21 
22     s = (snode*) malloc(sizeof(snode));
23     s->next = NULL;
24 
25     va_start(list, elem);
26     while (elem)
27     {
28         setinsert(s, elem);
29         elem = va_arg(list, int);
30     }
31     va_end(list);
32     return s;
33 } // createset

 

关于c – 如何在GCC上创建va_list?gcc创建c文件的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于android – 如何在主屏幕上创建VPN连接快捷方式?、c – 如何实施“__builtin_va_list”?、c – 重用va_list、c函数中传递可变参数:va_list,va_start,va_arg,va_end的相关信息,请在本站寻找。

本文标签: