C警告函数调用中缺少标记

amb*_*ika 41 c warnings

这是我的警告.

Missing sentinel in function call
Run Code Online (Sandbox Code Playgroud)

我怎么能删除它.

我正在使用linux和gcc编译器.

Mic*_*ord 64

看起来您可能没有终止数组声明NULL.如果没有null,你可能会有一些内存怪异,因为运行时不知道数组的结束位置和下一位内存的开始.

  • `nil`?这在C中不存在,只有NULL.这个答案有多少赞成?我肯定错过了什么. (2认同)

Pet*_*all 47

我刚遇到同样的问题.导致它的代码是......

execl("/bin/bash", "/bin/bash", fname, '\0');
Run Code Online (Sandbox Code Playgroud)

但它应该......

execl("/bin/bash", "/bin/bash", fname, (char *)0);
Run Code Online (Sandbox Code Playgroud)

第一个版本的问题是参数列表意味着以空指针结束.但'\ 0'不是空指针,而是空字符.所以值(0)是正确的,它只是类型错误.

(char*)0也是零,但是作为char 指针强制转换,它是一个空指针(即它指向地址0).这是必需的,因此系统可以告诉参数列表的结束位置,以便在最后一个参数列表之后不会继续扫描参数.这样做会得到无效的指针,可能指向任何内存 - 这可能会导致分段错误.

那个(char*)0被称为sentinel,它是第一个例子中缺少的东西.

最后请注意,NULL定义为(void*)0,所以

execl("/bin/bash", "/bin/bash", fname, NULL);
Run Code Online (Sandbox Code Playgroud)

同样有效,而且更方便一点.(感谢@mah).

  • 几分钟前我遇到了同样的问题.在我的情况下,我的呼叫已经以"0"终止,但警告已经存在; 当我用`NULL`替换它时,警告消失 - 出于与你相同的原因 - 指针转换为`NULL`. (3认同)

小智 18

在Xcode中,如果使用objective-c进行编码,并且使用的是一些采用变量参数列表的方法,则需要在列表末尾添加nil对象.

例如:

N SArray*names = [NSArray arrayWithObjects:@"Name1",@"Name2"]; //将导致上述警告

但是, NSArray*names = [NSArray arrayWithObjects:@"Name1",@"Name2",nil]; //正确

希望这会有所帮助!


Cir*_*四事件 11

使用(void*)0(void *)NULL代替NULL

警告sentinelJichao提到的function属性生成.记录于:https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Function-Attributes.html#index-g_t_0040code_007bsentinel_007d-function-attribute-3226其中说:

对于任何指针类型,此上下文中的有效NULL定义为零.如果您的系统使用整数类型定义NULL宏,则需要添加显式强制转换.GCC用一个适当重新定义NULL的副本替换stddef.h.

在ANSI C中,NULL可以是0或者(void *)0,但只有指针满足此属性,另请参见:NULL,'\ 0'和0之间有什么区别

虽然0将使用常规指针参数转换为空指针,但是不可能将零指针的零整数与vararg区分开来,因此差异至关重要.请参阅:指针的默认参数提升

是的,GCC保证NULL为指针,因为NULL由GCC提供stddef.h(某些ANSI C头在GCC中,其他在glibc中),我不确定这是否可能被破坏,因为它sentinel是一个GCC扩展开始.

但我仍然会写(void *)NULL(void*)0只是为了确定.

此外,POSIX和execl()函数终止都man execl需要"空指针",这是Sentinel使用的典型示例.

NULL不能保证在那里工作,因为它是一个"空指针常量",它不一定是"空指针",因此通过使用(void *)0到处都可以使您熟悉已知的API.另请参见:((void*)0)空指针常量?|| (int*)0是否为空指针?

GCC 5.2.0 execl 以内置方式提供并以sentinel编程方式设置:

DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECL, "execl", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_SENTINEL_NOTHROW_LIST)
Run Code Online (Sandbox Code Playgroud)

还有一个glibc 2.21版本execl没有该属性.


Jic*_*hao 5

一个简单的例子:

#include <stdio.h>
#include <stdarg.h>

void print_strings(const char* first, ...) __attribute__((sentinel));

void print_strings(const char* first, ...)
{
    va_list ap;
    const char* tmp;
    if (!first)
        return ;
    printf("%s\n", first);
    va_start(ap, first);
    while (1) {
        tmp = va_arg(ap, const char*);
        if (tmp == 0)
            break;
        printf("%s\n", tmp);
    };
    va_end(ap);
}

int main()
{
    print_strings("how are you?", "i'm fine", "and you?", NULL);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在 main 中,如果你调用 print_strings asprint_strings("how are you?", "I'm fine", "and you?")没有结尾NULL,GCC 会抱怨“缺少哨兵”。

因为我们在函数中添加了哨兵函数属性print_strings。它是一个 gcc 扩展,用于指定变量参数应以 NULL 结尾。因此,如果您不以 NULL 结束变量参数,编译器可以检测到它并显示警告。