我有一个函数,它传递一个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 ++之间是否存在差异?
答案 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进行比较。
这不方便,但它确实更安全,您可以在应用程序的多个位置使用此功能。考虑代码的可重用性是一个很好的习惯。