c中的静态初始化

时间:2009-12-31 20:22:39

标签: c++ c static

我有一个函数,它传递一个int列表,直到一个值为“-1”并计算最小值。

如果函数被多次调用,则应该在所有调用之间返回最小值。

所以我写了类似的东西:

int min_call(int num, ...)
{
    va_list argptr;
    int number;

    va_start(argptr, num);

    //static int min = va_arg(argptr, int); //////// the questioned line

    static int all_min = -1;

    int min = va_arg(argptr, int);

    if (min != -1)
    {
        while ((number = va_arg(argptr, int)) != -1)
        {
            if (number < min)
            {
                min = number;
            }

        }
    }

    if (min < all_min || all_min == -1)
    {
        all_min = min;
    }

    return all_min;
}

我想知道有关标记线的内容......为什么我不能称之为 - 编译器说因为用于初始化静态int的表达式不是常量。

出于某种原因,我记得我可以初始化一个静态变量,并且知道初始化语句只会被调用一次(第一次),它是用C ++编写的。 如果该行可用,它将为我节省几个变量。

在这个问题上,C和C ++之间是否存在差异?

6 个答案:

答案 0 :(得分:8)

是的,C ++允许在运行时懒惰地初始化静态。有效的C ++将静态初始化转换为:

static int XX_first_time = 1;
if (XX_first_time)
{
    // run the initializer
    XX_first_time = 0;
}

虽然这很方便,但它不是线程安全的。该标准并不要求这是线程安全的,尽管有些编译器已经这样做了(gcc 4.x进行线程安全初始化,除非明确要求不使用 -fno-threadsafe-statics )。

C要求静态是在编译时配置它们的值。是的,这是更有限的,但更符合C背后为你做的小工作(C可以被认为是便携式装配)。

答案 1 :(得分:4)

C静态初始化必须使用常量值,即在编译时已知的内容。由于您对va_arg()的调用在运行时才会解析,因此您无法将其用作静态初始值设定项。您可以在初始化时为min分配一个已知错误的值,然后在变量初始化之后简单地调用va_arg()(John Dibling的示例代码就是这样)。

另外,重要的是要注意静态初始化仅在每个范围内发生一次(在本例中为您的函数),因此即使您的注释掉的行有效,它也只会执行一次而不是每次调用该函数时(我认为你在期待)。

答案 2 :(得分:4)

正如其他人所说,在C中,必须使用编译时常量初始化static个变量。如果省略初始值,则将其视为0

现在,关于你的函数中的逻辑。我认为函数编写得更清楚(我没有改变函数的形式):

#include <limits.h>

int min_call(int num, ...)
{
    va_list argptr;
    int number;
    static int min = INT_MAX;

    va_start(argptr, num);

    while ((number = va_arg(argptr, int)) != -1)
        if (number < min)
            min = number;

    va_end(argptr);
    return min;
}

如果num也应包含在最低值的计算中,那么您需要在if (num < min) min = num;的行中进行额外的检查。

我也无法理解if (min < all_min || all_min == -1 )行。由于all_min在开始时已初始化为-1,因此从未触及,if条件始终为真。

请注意,正如其中一条评论所说,min的初始化是INT_MAX而不是INT_MIN,我们必须致电va_end()

答案 3 :(得分:2)

你不能做你想要做的事,因为静态在程序开始运行之前初始化 - argptr在上下文中还不存在。你可以尝试这样的事情:

va_start( argptr, num );

static bool  init = 0;
static int min = -1;
if( !init )
{
   min = va_arg( argptr, int );
   init = true;
}

static int all_min = -1;

答案 4 :(得分:2)

静态并不仅仅意味着它只会设置您调用它的第一个时间。这意味着它在编译时设置 。编译器不知道如何在编译时调用va_arg函数。 (除非你在运行时运行程序并传递参数,否则没有任何意义。)

编辑 - 在C.其他人注意到C ++不同。)

答案 5 :(得分:2)

这并不能完全回答你的问题,但其他答案已经做得很好。

但是,我认为你正在从错误的方向接近这个非常简单的问题。如果您希望您的功能可移植和可重复使用,您应该尽量减少它们的副作用。

例如,您应该将该数据保存在使用它的作用域的本地变量(或结构)中,而不是将状态数据保存在您的函数中(邪恶)。像这样:

{
    int min_so_far;

    min_so_far = min_call(NULL, 4, 7, 2, -6, 3, -12);
    min_so_far = min_call(&min_so_far, -11, 5, 3, 8, -3);

    printf("%d\n", min_so_far); //should output -12
}

min_call的第一个参数是int*,如果它作为NULL传入,那么函数会忽略它。否则,每个参数将与传入的int进行比较。

这不方便,但它确实更安全,您可以在应用程序的多个位置使用此功能。考虑代码的可重用性是一个很好的习惯。