C 中是否可以强制函数参数保持恒定?

Han*_*ans 4 c constants function

C 中有没有办法强制函数调用者向函数发送常量值(如果没有,则预期编译错误)?

例如,考虑这个简单的函数:

int foo(int x, int y)
{
    assert( x < 10);
    return x+y;
}
Run Code Online (Sandbox Code Playgroud)

如果我能以某种方式告诉编译器 x 在所有情况下都应该以常量值发送,则可以在编译时评估断言(即使断言实际上仅在运行时调用)。有办法这样做吗?

只是为了解释动机 - 在低资源系统中,在编译时评估事物可以显着降低软件占用空间和执行时间。

谢谢。

Sto*_*ica 5

首先也是最重要的,这是一个完全标准的 C11 解决方案:

#include <stdint.h>
#include <assert.h>

#define is_integral_constant_p(c) (_Generic(0 ? (void*)(uintptr_t)((c) - (c)) : (int*)(0), \
                                  int*: 1,                                            \
                                  default: 0)) 


#define foo(x, y) (is_integral_constant_p(x) ? real_foo : error_foo_x_is_not_a_constant_expression)(x, y)

extern int error_foo_x_is_not_a_constant_expression(int, int);
int real_foo(int x, int y)
{
    assert(x < 10);
    return x+y;
}

int main(void)
{
    static_assert(is_integral_constant_p(5), "5 is not a constant expression?");
    foo(5, 1);

    // int x = 0;
    // foo(x, 1);  // This will not link
}
Run Code Online (Sandbox Code Playgroud)

神奇之处在于条件表达式的工作原理。如果其中一个操作数是空指针常量,则结果的类型是另一个指针参数的类型。否则,如果一个参数是 a,则void*结果是void*。由于(void*)(0)是空指针常量,因此仅当(c) - (c)是整型常量表达式等于时,第二个操作数才是空指针常量0。当且仅当c是一个整型常量表达式时会发生这种情况。

只是_Generic根据结果的类型选择一个常量,我们期望该常量是int*在真实情况下,还是void*在其他情况下。更重要的是,宏本身计算为整数常量表达式(因此甚至可以在 中使用assert)。

以上是 Linux 内核中使用的技术的改编(如此处讨论的,只是没有 GNU 特定的 C 扩展。仅使用 C11 功能。

现在,我们实现foo为一个对 进行检查的宏x,并且转发到执行计算的“real_foo”,或者转发到已声明但未定义的函数。x因此,如果不是常量,程序将无法链接。

在这里观看直播。


对于您的特定情况,您可以完全删除断言并将检查移至宏中foo。它看起来像这样:

#define foo(x, y) (is_integral_constat_p(x) && (x < 10) ? real_foo : \
                   error_foo_x_is_not_a_constant_expression_or_more_than_10)(x, y)
Run Code Online (Sandbox Code Playgroud)

宏与短路评估相结合,为我们提供了您想要的行为。正如你在这里看到的。

在这一点上我觉得我应该提醒你。这段代码在代码审查中可能不太容易受到保护。因此,请仔细考虑您可能获得的任何性能提升是否值得解释。