-1 不小于 12?
-1 not less than 12?
我有 C 语言的小程序(子字符串):
char *str_sub(char *string, int from, int to) {
assert(to < 0 || from < to);
if (!(to < strlen(string))) {
printf("%d %ld\n", to, strlen(string));
}
assert(from < strlen(string) && to < strlen(string));
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=10=]';
当我将 -1 传递给 to
时,我想让函数匹配字符串的其余部分,但这并不重要。你看到第二个断言了吗?当我将 -1 传递给 to
时,它会引发错误,在上述情况下它也会显示 false
,但它只是 -1 和 12,正如我们从学校知道的那样,-1 < 12。
那么问题出在哪里?
您正在比较具有不同符号的变量,因此 -1
的表示在它们之间不统一。另请参阅评论中引用的@Shafik Yaghmour 的 SO 答案。
我可以像这样显示来自编译器的警告:
$ clang -Wsign-compare -c sign.c
sign.c:9:14: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
if (!(to < strlen(string))) {
~~ ^ ~~~~~~~~~~~~~~
sign.c:13:17: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
assert(from < strlen(string) && to < strlen(string));
~~~~ ^ ~~~~~~~~~~~~~~
/usr/include/assert.h:89:5: note: expanded from macro 'assert'
((expr) \
^
sign.c:13:40: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
assert(from < strlen(string) && to < strlen(string));
~~ ^ ~~~~~~~~~~~~~~
/usr/include/assert.h:89:5: note: expanded from macro 'assert'
((expr) \
^
$ cat sign.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char *str_sub(char *string, int from, int to) {
assert(to < 0 || from < to);
if (!(to < strlen(string))) {
printf("%d %ld\n", to, strlen(string));
}
assert(from < strlen(string) && to < strlen(string));
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=10=]';
return result;
}
strlen
returns 一个 size_t
(无符号相关)变量,并且在进行任何比较之前,两个变量必须具有相同的类型。所以,其中一个必须转换为另一个。
在您的示例中,我确定 to
已转换为 unsigned
,导致溢出 (-1),并且您可能正在将 strlen(string)
与可表示的最大值进行比较无符号整数(溢出的可能结果)。
所以,解决方案是:
char *str_sub(char *string, int from, int to) {
assert(to < 0 || from < to);
if (!(to < (int)strlen(string))) {
printf("%d %ld\n", to, strlen(string));
}
assert(from < strlen(string) && to < (int)strlen(string));
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=10=]';
或者,为了避免重新计算:
char *str_sub(char *string, int from, int to) {
int length = strlen(string);
assert(to < 0 || from < to);
if (!(to < length)) {
printf("%d %ld\n", to, length);
}
assert(from < length && to < length);
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=11=]';
或者,为了进行安全转换,时间过长 string
s(感谢您的评论,@chux):
char *str_sub(char *string, int from, int to) {
size_t length = strlen(string);
assert(length > 0);
assert(to < 0 || from < to);
if (!(to > 0 && to < length))
printf("%d %lu\n", to, length);
assert(from < length);
assert(to < 0 || to < length);
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=12=]';
比较运算符假定您比较的两个变量属于同一类型。事实并非如此,“-1”无符号作为有符号变量的二进制表示完全不是“-1”,而是变量的最大值。
很多人说过,to < strlen(string)
比较 (size_t)-1 < strlen(string)
。由于 size_t
是某种无符号类型,因此 (size_t)-1
是一个很大的正值,这种比较经常失败。
修复:考虑 size_t
。
char *str_sub(char *string, int from, int to) {
assert(to < 0 || from < to);
assert(from >= 0);
size_t length = strlen(string);
size_t uto = to < 0 ? length : to;
assert(from < uto);
if (!(uto < strlen(string))) {
printf("%zu %zu\n", uto, strlen(string));
}
assert(from < length && uto < length);
char *result = malloc(uto - from + 1);
// memcpy(result, &string[from], to);
memcpy(result, &string[from], uto - from);
// result[to] = '[=10=]';
result[uto - from] = '[=10=]';
return result;
}
注意:而不是所有这些 assert()
,建议为 from,to
的所有组合定义操作。
from
和 to
不是 int
,而是使用 size_t
并创建 #define MATCH_REST ((size_t)-1)
。示例:
#define MATCH_REST ((size_t)-1)
char *str_sub(const char *string, size_t from, size_t to) {
size_t length = strlen(string);
if (to > length) to = length;
if (from > to) from = to;
size_t diff = to - from;
char *result = malloc(diff + 1);
if (result) {
memcpy(result, &string[from], diff);
result[diff] = '[=11=]';
}
return result;
}
我有 C 语言的小程序(子字符串):
char *str_sub(char *string, int from, int to) {
assert(to < 0 || from < to);
if (!(to < strlen(string))) {
printf("%d %ld\n", to, strlen(string));
}
assert(from < strlen(string) && to < strlen(string));
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=10=]';
当我将 -1 传递给 to
时,我想让函数匹配字符串的其余部分,但这并不重要。你看到第二个断言了吗?当我将 -1 传递给 to
时,它会引发错误,在上述情况下它也会显示 false
,但它只是 -1 和 12,正如我们从学校知道的那样,-1 < 12。
那么问题出在哪里?
您正在比较具有不同符号的变量,因此 -1
的表示在它们之间不统一。另请参阅评论中引用的@Shafik Yaghmour 的 SO 答案。
我可以像这样显示来自编译器的警告:
$ clang -Wsign-compare -c sign.c
sign.c:9:14: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
if (!(to < strlen(string))) {
~~ ^ ~~~~~~~~~~~~~~
sign.c:13:17: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
assert(from < strlen(string) && to < strlen(string));
~~~~ ^ ~~~~~~~~~~~~~~
/usr/include/assert.h:89:5: note: expanded from macro 'assert'
((expr) \
^
sign.c:13:40: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
assert(from < strlen(string) && to < strlen(string));
~~ ^ ~~~~~~~~~~~~~~
/usr/include/assert.h:89:5: note: expanded from macro 'assert'
((expr) \
^
$ cat sign.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char *str_sub(char *string, int from, int to) {
assert(to < 0 || from < to);
if (!(to < strlen(string))) {
printf("%d %ld\n", to, strlen(string));
}
assert(from < strlen(string) && to < strlen(string));
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=10=]';
return result;
}
strlen
returns 一个 size_t
(无符号相关)变量,并且在进行任何比较之前,两个变量必须具有相同的类型。所以,其中一个必须转换为另一个。
在您的示例中,我确定 to
已转换为 unsigned
,导致溢出 (-1),并且您可能正在将 strlen(string)
与可表示的最大值进行比较无符号整数(溢出的可能结果)。
所以,解决方案是:
char *str_sub(char *string, int from, int to) {
assert(to < 0 || from < to);
if (!(to < (int)strlen(string))) {
printf("%d %ld\n", to, strlen(string));
}
assert(from < strlen(string) && to < (int)strlen(string));
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=10=]';
或者,为了避免重新计算:
char *str_sub(char *string, int from, int to) {
int length = strlen(string);
assert(to < 0 || from < to);
if (!(to < length)) {
printf("%d %ld\n", to, length);
}
assert(from < length && to < length);
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=11=]';
或者,为了进行安全转换,时间过长 string
s(感谢您的评论,@chux):
char *str_sub(char *string, int from, int to) {
size_t length = strlen(string);
assert(length > 0);
assert(to < 0 || from < to);
if (!(to > 0 && to < length))
printf("%d %lu\n", to, length);
assert(from < length);
assert(to < 0 || to < length);
char *result = (char *) calloc(to - from + 1, 1);
memcpy(result, &string[from], to);
result[to] = '[=12=]';
比较运算符假定您比较的两个变量属于同一类型。事实并非如此,“-1”无符号作为有符号变量的二进制表示完全不是“-1”,而是变量的最大值。
很多人说过,to < strlen(string)
比较 (size_t)-1 < strlen(string)
。由于 size_t
是某种无符号类型,因此 (size_t)-1
是一个很大的正值,这种比较经常失败。
修复:考虑 size_t
。
char *str_sub(char *string, int from, int to) {
assert(to < 0 || from < to);
assert(from >= 0);
size_t length = strlen(string);
size_t uto = to < 0 ? length : to;
assert(from < uto);
if (!(uto < strlen(string))) {
printf("%zu %zu\n", uto, strlen(string));
}
assert(from < length && uto < length);
char *result = malloc(uto - from + 1);
// memcpy(result, &string[from], to);
memcpy(result, &string[from], uto - from);
// result[to] = '[=10=]';
result[uto - from] = '[=10=]';
return result;
}
注意:而不是所有这些 assert()
,建议为 from,to
的所有组合定义操作。
from
和 to
不是 int
,而是使用 size_t
并创建 #define MATCH_REST ((size_t)-1)
。示例:
#define MATCH_REST ((size_t)-1)
char *str_sub(const char *string, size_t from, size_t to) {
size_t length = strlen(string);
if (to > length) to = length;
if (from > to) from = to;
size_t diff = to - from;
char *result = malloc(diff + 1);
if (result) {
memcpy(result, &string[from], diff);
result[diff] = '[=11=]';
}
return result;
}