gcc:Double-NULL-sentinel属性?

gcc:Double-NULL-sentinel属性?,gcc,attributes,sentinel,Gcc,Attributes,Sentinel,我有一个变量函数,它需要一个双空终止符 人为的、简化的例子 我想给它加上注释。但是,对于sentinel属性,只有一个参数可以要求为NULL,而不是所需的sentinel(0,1)[最后两个参数要求为NULL] 有没有办法要求gcc强制执行双空,或者 鉴于NULL只能对两个参数中的一个强制执行,您会用sentinel(0)或sentinel(1)来修饰此函数吗?为什么?这两个位置中的哪一个更容易捕获bug?如果两个哨兵中的任何一个丢失,可能实现编译错误的唯一方法是使用C99: #包括 #包括 #

我有一个变量函数,它需要一个双空终止符

人为的、简化的例子

我想给它加上注释。但是,对于sentinel属性,只有一个参数可以要求为NULL,而不是所需的sentinel(0,1)[最后两个参数要求为NULL]

有没有办法要求gcc强制执行双空,或者


鉴于NULL只能对两个参数中的一个强制执行,您会用sentinel(0)或sentinel(1)来修饰此函数吗?为什么?这两个位置中的哪一个更容易捕获bug?

如果两个哨兵中的任何一个丢失,可能实现编译错误的唯一方法是使用C99:

#包括
#包括
#包括
#pragma GCC诊断错误“-Wformat”
void checkSentinel0(字符*名称,…)\uuuuuu属性(sentinel(0));
void checkSentinel1(字符*名称,…)\uuuuuu属性(sentinel(1));
void checkSentinel0(字符*名称,…){
(无效)姓名;
}
void checkSentinel1(字符*名称,…){
(无效)姓名;
}
#定义MY_VARIADIC(name,…)do{checkSentinel0(name,uu VA_ARGS_uu)\
checkSentine1(名称、参数)\
myVariadic(名称,uu VA_uargs_uuu)}\
而(0);
无效变量(字符*名称,…){
//你的代码弄乱了坐标等等。
(无效)姓名;
}
int main(){
MY_VARIADIC(“test”,1,2,3,4,NULL,NULL);//确定
MY_VARIADIC(“test”,1,2,3,4,14,15);//不可编译
MY_VARIADIC(“test”,1,2,3,4,NULL,15);//不可编译
MY_VARIADIC(“test”,1,2,3,4,15,NULL);//不可编译
返回0;
}

因此,如果用户只接触到您的宏
MY_VARIADIC
,那么他/她将出现错误,以防忘记用两个空值终止参数列表。

请澄清您的示例是多么精心设计和简化<代码>\uuuu属性\uuuuu((sentinel))根本不适合检查整数0-在编译器不知道类型的上下文中,这不一定与空指针相同(如可变函数)。正如您链接到的文档所述:“此函数属性确保函数调用中的参数是显式的
NULL
[…]在此上下文中,有效的
NULL
被定义为具有任何指针类型的零。[…]”。显然,它们太过做作了,应该是指针,而不是整数。其目的是澄清NULL不会被解释为合法坐标(因为值为0的指针和值为0的整数到Naive变量函数将无法区分)。我试图把这个问题提炼出来-并不是想在这个过程中引入混乱。请再次阅读假设
任何合法的x或y不能为0
,并认为您真的需要两个空值吗?人为示例的缺陷,已编辑以修复
void makeLine(char *name, ...) {
    ... accepts (x,y) coordinates until (0,0) is found,
    ... assume that any coordinate except (0,0) is legal
            [i.e. (0,1) or (1,0) should not trigger a stop condition]
}
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#pragma GCC diagnostic error "-Wformat"

void checkSentinel0(char * name, ...) __attribute__ ((sentinel(0)));
void checkSentinel1(char * name, ...) __attribute__ ((sentinel(1)));

void checkSentinel0(char * name, ...) {
    (void)name;
}
void checkSentinel1(char * name, ...) {
    (void)name;
}

#define MY_VARIADIC(name, ...) do {checkSentinel0(name, __VA_ARGS__);\
                                   checkSentinel1(name, __VA_ARGS__);\
                                       myVariadic(name, __VA_ARGS__);}\
                               while(0);

void myVariadic(char * name, ...) {
    // your code messing with coordinates and etc.
    (void)name;
}

int main () {

 MY_VARIADIC("test", 1,2,3,4, NULL, NULL); // Ok

 MY_VARIADIC("test", 1,2,3,4, 14,     15); // not compilable
 MY_VARIADIC("test", 1,2,3,4, NULL,   15); // not compilable
 MY_VARIADIC("test", 1,2,3,4, 15,   NULL); // not compilable

 return 0;
}