我不确定我是否选择了正确的 Headers ,但今天我发现(作为C语言的初学者)对我来说strlen并不总是在我需要时做出正确的决定 .
所以我尝试了以下内容:
#include<stdio.h>
#include<string.h>
int foo(char *s){
int len = strlen(s);
/* code here */
return len;
}
int main(void){
char *name = "Michi";
int len = foo(name);
int a = 20, b = 10, c = a - b;
if(c < len){
printf("True: C(%d) < Len(%d)\n",c,len);
}else{
printf("False: C(%d) > Len(%d)\n",c,len);
}
return 0;
}
输出:
错误:C(10)> Len(5)
但当我用“ -Wconversion ”编译时,我得到:
program.c:5:19:警告:从'size_t'转换为'int'可能会改变其值[-Wconversion]
int len = strlen(s);
^
快速解决方法是施放strlen:
int len = (int)strlen(s);
但我不同意,所以我决定我真的需要别的东西,另一种方法可能呢?我尝试了以下方法:
#include<stdio.h>
#include<string.h>
unsigned int size(char *s){
unsigned int len;
/* code here */
len = (unsigned int)strlen(s);
return len;
}
int main(void){
char *name = "Michi";
unsigned int len = size(name);
int a = 20, b = 10, c = a - b;
if(c < (signed int)len){
printf("True: C(%d) < Len(%d)\n",c,len);
}else{
printf("False: C(%d) > Len(%d)\n",c,len);
}
return 0;
}
但我仍然需要强制转换strlen因为它的返回类型(size_t,我知道这是一个无符号类型( typedef long unsigned int size_t; ))
最后,我决定采用另一种方法,创建自己的函数,这样可以使事情变得更容易,并且将来可能的问题更少,我得到了:
#include<stdio.h>
long int stringLEN(char *s){
int i = 0;
long int len = 0;
while (s[i] != '\0'){
len++;
i++;
}
return len;
}
long int foo(char *s){
long int len = stringLEN(s);
/* code here */
return len;
}
int main(void){
char *name = "Michi";
long int len = foo(name);
int a = 20, b = 10, c = a - b;
if(c < len){
printf("True: C(%d) < Len(%ld)\n",c,len);
}else{
printf("False: C(%d) > Len(%ld)\n",c,len);
}
return 0;
}
那里不再需要演员阵容了 .
所以我的问题是:这是(对于我的情况)更好的方法吗?如果不是我需要一些解释,我的书(我有3个)并没有以这种方式解释我能够理解这些事情 .
我知道只是在某种程度上 cast 可能是个大问题 .
编辑:此代码也不会与 -Wconversion 编译:
#include<stdio.h>
#include<string.h>
size_t foo(char *s){
size_t len = strlen(s);
/* code here */
return len;
}
int main(void){
char *name = "Michi";
size_t len = foo(name);
int a = 20, b = 10, c = a - b;
if(c < len){
printf("True: C(%d) < Len(%zu)\n",c,len);
}else{
printf("False: C(%d) > Len(%zu)\n",c,len);
}
return 0;
}
输出:
error:有符号和无符号整数表达式之间的比较[-Werror = sign-compare] |
但如果我投了 len 的作品 . 我意识到,如果尺寸大于那么 int 它将永远不适合 .
6 回答
挖掘所有其他答案,你真正的问题似乎是如何处理这样的情况:
...在哪里你不能改变
slen
或value
的类型,因为两者都是正确的API,他们收到的结果 .-Wconversion
警告试图告诉你一些有意义的事情 . C中有符号和无符号整数类型的比较做了一些非常奇怪的事情,而不是你对_321776中算术定律的期望;像我上面写的那样天真的比较可以并且已经造成了灾难性的错误 . 但治愈不是铸造或发明自己的strlen
;治愈是为了确定比较,以便它符合你对算术规律的期望 . 其原则是:首先检查签名数量是否为负数 . 如果是这样,请将其视为小于无符号数量 .
否则,在比较它们之前,将较小的类型转换为较大的类型 .
在这种情况下,
size_t
几乎肯定比int
大,或者大小相同,所以你会写static_assert
存在是因为,如果我没记错的话,C标准不保证size_t
至少与unsigned int
一样大 . 例如,我可以想象一下80286的ABI,其中int
是四个字节宽但size_t
只有两个 . 在那种情况下,您需要以相反的方式进行投射:如果您不知道哪些是签名的,那么您在标准C中的唯一办法就是
(u)intmax_t
:......而且,鉴于C99 wrt
long
设定了非常不幸的先例,可能会有一天(u)intmax_t
不是编译器支持的最大整数类型,然后你只是被冲洗了 .字符串的长度永远不会是负数,而整数可能是 - 警告是因为
size_t
的值范围与int
不同,如果强制转换为int
,则size_t
的某些正值将被视为负数 . 更好的选择是让函数的返回类型匹配,在这种情况下,让foo
返回一个size_t
- 你很快就会看到数据类型会覆盖大部分代码,并留下一些其他奇怪的东西可以做奇怪的事情(size_t - size_t
可能下流...)解决此问题的常用方法是使用键入
size_t
的变量,并选择适当的格式进行打印 . 然后不需要演员阵容 . 对于printf,请参阅以下内容:printf format specifiers for uint32_t and size_t
What's the correct way to use printf to print a size_t?
我认为从编译器到编译器必须有所不同.....因为我在在线编译器上尝试过它并没有显示任何警告 .
这将在没有警告的情况下编译:
在@thomasdickey,@ onlandshaw,@ andreaghidini,@ olaf,@ juanchopanza等人的回答和评论中也有所解释 .
你真的做得更好吗?不:为什么stringlen函数会返回可能为负值的值?没有负大小的字符串 .
标准的strlen函数已经存在,效率更高,能够处理字符串,其最大大小是stringLEN处理的最大大小的两倍,并且具有更精确的返回类型定义 .
有两个问题:
strlen()
返回类型size_t
.size_t
是一些无符号整数类型,可能比int
宽或宽 . 它取决于编译器/平台 .代码需要比较和
int
到size_t
. 因为size_t
是无符号的,所以防止混合签名/无符号比较的警告,显式将int
更改为无符号整数 . 要将非负int
更改为无符号整数,请强制转换为(unsigned)
.要比较,测试
c
是否为负数,如果不是,则将(unsigned)c
直接与len
进行比较 . 编译器将根据需要隐藏类型,并产生算术正确的答案 ...