正确使用strncmp

正确使用strncmp,c,C,下面是快速的背景:我有一个客户端和一个服务器程序,它们通过Unix套接字相互通信。在服务器端解析接收到的消息时,我试图使用strncmp来确定要采取的操作 我遇到的问题是弄清楚strncmp的length参数到底要用什么。这个问题的原因是我的一些邮件共享一个公共前缀。例如,我有一条消息“getPrimary”,它使服务器以主服务器地址响应,还有一条消息“getPrimaryStatus”,它使服务器以主服务器的状态响应。我最初的想法是这样做: if(strncmp(message,"getPri

下面是快速的背景:我有一个客户端和一个服务器程序,它们通过Unix套接字相互通信。在服务器端解析接收到的消息时,我试图使用strncmp来确定要采取的操作

我遇到的问题是弄清楚strncmp的length参数到底要用什么。这个问题的原因是我的一些邮件共享一个公共前缀。例如,我有一条消息“getPrimary”,它使服务器以主服务器地址响应,还有一条消息“getPrimaryStatus”,它使服务器以主服务器的状态响应。我最初的想法是这样做:

if(strncmp(message,"getPrimary",strlen("getPrimary"))==0){
    return foo;
}
else if(strncmp(message,"getPrimaryStatus",strlen("getPrimaryStatus"))==0){
    return bar;
}
问题是,当我发送服务器“getPrimaryStatus”时,代码将始终返回foo,因为strncmp在字符串中检查得不够远。我可以将strlen(message)作为length参数传递给strncmp,但这似乎违背了使用strncmp的目的,它是为了防止意外输入时溢出。对于我可以读取的最大消息长度,我确实有一个静态变量,但似乎传入了这个变量,因为这个长度只是确保如果消息溢出,效果会最小化

我已经提出了一些解决方案,但它们不是很漂亮,所以我想知道是否有一个共同的方式来处理这个问题

作为参考,我目前的解决方案是: 对我的if/else if语句进行排序,以便按照长度递减的顺序检查任何带有公共前缀的消息(这似乎是一个很好的方法,可以在我的代码中为以后试图添加内容的人埋下一颗地雷)

将带有常用前缀的“我的邮件”分组,然后首先查找后缀:

if(strncmp(message,"getPrimary",strlen("getPrimary"))==0){
    if(strncmp(message,"getPrimaryStatus",strlen("getPrimaryStatus"))==0){
        return bar;
    else
        return foo;
    }
}
但这感觉很混乱,特别是因为我正在处理大约20条不同的消息

创建一个包含所有可能消息的数组,在我的init序列中添加一个函数,该函数将按长度降序排列数组,并让我的代码搜索该列表的元素,直到找到匹配项。这似乎既复杂又愚蠢

似乎这应该是一个足够普遍的问题,应该有一个解决方案,但我还没有找到任何东西到目前为止


提前感谢您的帮助

从我一年前做C编程的记忆中挖掘出来,我认为第三个参数应该告诉函数要处理多少个字符来进行比较。这就是为什么它是安全的,因为您可以控制要处理多少个字符

所以应该是这样的:

if(strncmp(message, "getPrimary", strlen("getPrimary")) {
   //
}

不要使用
strncmp()
。改用
strlcmp()
。更安全。

我感觉您正在使用strncmp来防止缓冲区溢出,但是,消息已经复制到内存中(即消息缓冲区)。另外,原型

int strncmp ( const char * str1, const char * str2, size_t num );
表示该函数没有副作用(即它不会更改任何一个输入缓冲区),因此不应存在覆盖缓冲区和更改内存的风险。(strcpy()的情况并非如此。)

您可以确保消息缓冲区的长度大于最长的命令字符串。这样,您就可以确保始终访问自己拥有的内存

此外,如果您坚持使用strncmp,您可以将命令列表存储在一个数组中,并将其从最大到最小排序。您可以将每个字符串与一个长度(可能还有一个执行处理程序的函数指针)相关联


最后,你可以找到C版本的C++调用地图或者露比或PHP调用关联数组的C版本。这使库能够高效、正确地处理此if-else树。

您的消息是否只包含这些命令中的一个,或是后跟空格/开括号/等的命令字符串

如果是前者,请放下strncmp,只使用strcmp


如果是后者,只需检查
isspace(message[strlen(command)])
message[strlen(command)]='('
或类似项即可。(注意:
strlen(command)
是一个常量,您可能应该这样编写它,或者使用宏从字符串文本的大小获取它。)

一种方法是先比较最长的名称,然后对测试(或包含关键字的表格)排序,以便名称越长越短。但是,以您的示例为例:

GetPrimaryStatus
GetPrimary
您可能希望确保
GetPrimaryIgnition
不被识别为
GetPrimary
。因此,您确实需要使用两个字符串中较长字符串的长度(消息或关键字)进行比较

此处的数据结构可能是:

static const struct
{
    char   *name;
    size_t  name_len;
    int     retval;
} Messages[] =
{
    { "getPrimaryStatus", sizeof("getPrimaryStatus"), CMD_PRIMARYSTATUS },
    { "getPrimary",       sizeof("getPrimary"),       CMD_PRIMARY       },
    ...
};
然后,您可以在此表中循环查找相关命令。您可以谨慎地限制必须查看的范围。请注意,
sizeof()
值包括字符串末尾的NUL。如果您可以使用null终止消息,则此选项非常有用

但是,如果您可以通过将消息复制到某个位置或在原地修改消息,以null终止消息中的命令字,这是迄今为止最简单的方法。然后使用
strcmp()
而不是
strncmp()
。最短的唯一前缀查找更难编码


查找命令字的一种可行方法是使用
strcspn()
——假设您的命令都是字母或字母数字。

假定
消息中的字符串应该以null结尾,这是在此处使用
strncmp()
而不是
strcmp()的唯一原因如果
消息
不是以null结尾,则应防止其超出
消息
的结尾

因此,传递给
strncmp()
n
应该是您应该知道的
消息的接收大小(从
read()
/
recv()
函数的返回值
/* len is a placeholder for whatever variable or function you use to get the length */
if ((len(a) == len(b)) && (strncmp(a, b, len(a)) == 0))
{
    /* Strings are equal */
}