C语言不定长参数的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言不定长参数的问题相关的知识,希望对你有一定的参考价值。

情况是这样的,一个while循环(最多的情况15个左右),循环中,要不停的输出log信息。log信息的处理,类似于printf函数。
由于log信息是写到pci卡中的,因此,处理log信息时间较长。造成整个while循环执行的时间有点长。

希望能改进的是:执行while循环的时候,将所有log信息,保存起来;退出while循环之后,输出到PCI卡。
这就需要对不定长的参数进行处理,目前的处理是根据,log格式,将参数解析出来。

有没有一种方式,不对log信息进行处理;仅仅是将所有参数取出来,保存到数组中,最后一起处理。
我没有说清楚
while循环内部,会调用很多别的函数。log的格式,不一样。log输出,必须得用不定长参数。
while循环内部,将log信息,保存到数组或者链表中的方法,我尝试过。
问题在于:如何,保存每一条log信息的实参的值。(参数,不是定长)

说的有点混乱,提供几个方法。1,你的WHILE另开一个线程.2做一个LIST保存每个LOG的信息,每个信息是NEW出来的。

说实话,我还是没明白你补充的意思。
我写个伪代码吧,希望能有点启发
list <LOG_INFO*> info_list;
while ()

...//some function
//new出来的东西在堆上,不会被释放掉,所以一直都存在
LOG_INFO* log_info = new LOG_INFO();
//放到炼表里保存指针
info_list.push_back(log_info);
...//some function

output_log(info_list);//把炼表给输出的函数
release_info(info_list);//释放new的东西。

基本是这个意思,就是你new出来的东西不会被释放.
另外log_info可以是一个类,里面变的东西都可以设置,当然有的东西没有可以不设置.因为具体问题不清楚,所以可能更优化.

而输出的时候是根据类里面的成员变量进行输出的.

举例:
比如可能输出的是字符串也可能输出图片那么可以定义如下
class Info

string str;
Image image;
bool is_str;
bool is_image;

然后判断到底有什么,当然也可以用指针等其他方法进行数据结构的优化.
参考技术A log格式不一样,是指类型不一样吗?

是指log可能是不同的结构类型的?

不定长参数是指参数数量不同? 这个参数是输出到Pci的函数要用的参数?

你现在的描述,仍然很模糊,不妨给个例子说明一下。描述一下log可能的格式,输出到Pci函数等。

bug诞生记——不定长参数隐藏的类型问题

        这个bug的诞生源于项目中使用了一个开源C库。由于对该C库API不熟悉,一个不起眼的错误调用,导致一系列诡异的问题。最终经过调试,我们发现发生了内存覆盖问题。为了直达问题根节,我将问题代码简化如下(转载请指明出于breaksoftware的csdn博客)

#include <iostream>
#include <stdarg.h>

enum type 
    PARAM,
    RESULT
;

void set_zero(type t, ...) 
    va_list arg;
    va_start(arg, t);
    if (PARAM == t) 
        long* param_longp = va_arg(arg, long *);
        *param_longp = 0;
     else 
        int* param_intp = va_arg(arg, int *);
        *param_intp = 0;
    

    va_end(arg);


int main() 
    int x = 1;
    int y = 2;
    set_zero(PARAM, &y);
    std::cout << "x = " << x << "; y = " << y << std::endl;
    return 0;

        如果只是简单看一下main函数,可以认为输出是

x = 1; y = 0

        然而实际输出是

x = 0; y = 0

        是不是很诡异?我们在main函数中只是把y的值从2修改成0,根本没有“动”过x变量。但是最终x的值变成了0。

        由于示例足够简单,我们可以通过阅读源码来定位问题。第26行传递的参数y是4个字节的int类型。而在第13行,发现参数被当成8个字节的long类型设置为0,这样就覆盖了y空间之后的4个字节。而x变量正好在内存上位于y变量之后,这样x的值也会被改成0。

        现实中,我们的场景比较复杂,最终我们通过GDB来确定该问题。其过程大致如下

Reading symbols from ./test...done.
(gdb) b 26
Breakpoint 1 at 0xb0a: file main.cpp, line 26.
(gdb) r
Starting program: /home/fangliang/projects/test_cover/test 

Breakpoint 1, main () at main.cpp:26
26              set_zero(PARAM, &y);
(gdb) p &x
$1 = (int *) 0x7fffffffe434
(gdb) p x
$2 = 1
(gdb) p &y
$3 = (int *) 0x7fffffffe430
(gdb) p y
$4 = 2
(gdb) x/2x &y
0x7fffffffe430: 0x00000002      0x00000001
(gdb) awatch x
Hardware access (read/write) watchpoint 2: x
(gdb) c
Continuing.

Hardware access (read/write) watchpoint 2: x

Old value = 1
New value = 0
set_zero (t=PARAM) at main.cpp:21
21      
(gdb) disas
……
   0x0000555555554a64 <+234>:   mov    -0xd8(%rbp),%rax
   0x0000555555554a6b <+241>:   movq   $0x0,(%rax)
=> 0x0000555555554a72 <+248>:   jmp    0x555555554acb <set_zero(type, ...)+337>
……
   0x0000555555554acb <+337>:   nop
   0x0000555555554acc <+338>:   mov    -0xb8(%rbp),%rax
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) i r rax 
rax            0x7fffffffe430   140737488348208
(gdb) x/2x 0x7fffffffe430
0x7fffffffe430: 0x00000000      0x00000000

        第2行在代码第26行下了断点,为了让我们可以在main函数中查看x、y变量的地址和值。

        第10,14和18行可以看出x和y变量的内存空间是连续的。

        第19行我们给“莫名”被修改的变量x下了内存读写断点。执行continue后,由于x的值被从1改成0,从而触发了断点。

        第30行,我们查看当前代码处的汇编指令。

        第33行,是触发内存断点,即x的值被修改的位置。movq是给8个字节赋值,于是我们只要验证rax地址是否就是y变量的地址。

        第41行验证了rax地址就是y变量地址,从而可以证明就是movq   $0x0,(%rax)导致x变量值被改变。

        第43行,我们查看此时x和y的内存空间的值,它们已经都是0了。

        如果我们把set_zero方法改成针对y变量的函数

void set_param(long* param_longp) 
    *param_longp = 0;

        这样如果我们给其传递int型变量,编译器就会报错

main.cpp: In function ‘int main()’:
main.cpp:30:14: error: cannot convert ‘int*’ to ‘long int*’ for argument ‘1’ to ‘void set_param(long int*)’
  set_param(&y);

        而使用可变长参数则正好掩盖了该问题。

以上是关于C语言不定长参数的问题的主要内容,如果未能解决你的问题,请参考以下文章

C语言 函数不定长参数 ##__VA_ARGS__经典案例

44.不定长参数元组

bug诞生记——不定长参数隐藏的类型问题

C++不定参数

不定长参数可变参数

Python 不定长参数 *argc/**kargcs