在正确位置(`gcc`)获得编译警告

时间:2019-01-30 17:35:48

标签: c gcc compiler-warnings

this example powered by Godbolt中,并复制如下, 可以创建一个需要其参数遵守某些条件(i >= 0)ptr != NULL等的函数。

// EXPECT() : will trigger a warning if the condition is not guaranteed
#define EXPECT(c)  (void)((c) ? (void)0 : never_reach())

// assume() : tell the compiler that `cond` is true
// note : only works for simple conditions, such as `i>=0`.
// Avoid complex conditions invoking functions.
#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)


// *********************************************************
// Function declaration
// *********************************************************

int positive_plus1_body(int v); 
#define positive_plus1_preconditions(v)   ((v)>=0)     // Let's first define the preconditions. 
                                                       // Name is long, because conditions must be unique to the function

// The inlined function express the contract, with both pre and post conditions.
// `inline` is essential, so that actual input values get verified,
// and result gets enriched with `assume` conditions.
// Problem is, the error is now located INTO the inlined function, not at the place where it's called.
// This makes it very hard to identify where the problem happens.
static inline int positive_plus1(int v)                // Ideally, this function should also have additional attribute to not trigger warnings when it's not invoked
{
    int r;
    EXPECT(positive_plus1_preconditions(v));           // preconditions
    r = positive_plus1_body(v);
    assume(r > 0);                                     // postconditions
    return r;
}

通过Godbolt实时示例,可以调用参数正确和错误的函数,并见证对编译诊断的影响。

如果调用者不遵守条件,则编译器将生成警告。立即检测条件违规非常方便。常见的替代方法是在函数体内使用assert(),但是要依靠运行时测试来检测潜在的条件违规情况,这种情况不太即时,也不太确定。

问题是,如果用错误的参数调用inline函数,则编译器将在inline函数的内部 中定位条件违规。该诊断的作用有限。相反,我们想读取使用错误参数调用inline函数的行。

解决方法是改用宏。但是,宏将触发著名的多重评估问题,因为它的参数必须多次使用。这足以避免发生危险。另外,可以通过宏自动生成封装inline函数,但是另一个宏不能生成宏。

另一种解决方案是使用statement expression,它可以解决多重评估问题。但是,它是不可移植的,并且仍然是一个宏,因此不能由另一个宏生成。

如果可能的话,最好保留示例的inline函数。但是在条件违反发生的地方生成正确的行号非常重要。 有没有办法在保持inline函数方法的同时实现这一目标?

0 个答案:

没有答案