似乎strtol()
和strtod()
有效地允许(并强制)你在字符串中抛弃constness:
#include <stdlib.h>
#include <stdio.h>
int main() {
const char *foo = "Hello, world!";
char *bar;
strtol(foo, &bar, 10); // or strtod(foo, &bar);
printf("%d\n", foo == bar); // prints "1"! they're equal
*bar = 'X'; // segmentation fault
return 0;
}
上面,我自己没有进行任何演员表演。但是,strtol()
基本上会将const char *
投放到char *
中,而不会发出任何警告或其他任何内容。 (事实上,它不允许您将bar
键入const char *
,因此强制类型中的不安全更改。)这不是真的很危险吗?
答案 0 :(得分:13)
我猜是因为替代方案更糟糕。假设原型已更改为添加const
:
long int strtol(const char *nptr, const char **endptr, int base);
现在,假设我们要解析一个非常量字符串:
char str[] = "12345xyz"; // non-const
char *endptr;
lont result = strtol(str, &endptr, 10);
*endptr = '_';
printf("%s\n", str); // expected output: 12345_yz
但是当我们尝试编译这段代码时会发生什么?编译错误!这是非直观的,但您无法将char **
隐式转换为const char **
。有关原因的详细说明,请参阅C++ FAQ Lite。它在技术上谈论C ++,但参数对C同样有效。在C / C ++中,你只能隐式地从“指向 type ”的指针转换为“指向{{1}的指针”。最高级别的 type “:您可以执行的转换是从const
到char **
,或等效于”指向char * const *
的指针“ “指向(char
}指针{const
”。
因为我猜测解析非常量字符串比解析常量字符串的可能性要大得多,我会继续假设char
- 对于不太可能的情况的不正确性比使常见情况更好编译错误。
答案 1 :(得分:7)
是的,其他函数具有相同的“const-laundering”问题(例如strchr,strstr,所有那些)。
正是由于这个原因,C ++增加了重载(21.4:4):函数签名strchr(const char*, int)
被两个声明所取代:
const char* strchr(const char* s, int c);
char* strchr( char* s, int c);
但是当然在C语言中你不能同时拥有两个具有相同名称的const-correct版本,所以你得到了const错误的妥协。
C ++没有提到strtol和strtod的类似重载,事实上我的编译器(GCC)没有它们。我不知道为什么不这样做:你无法隐式地将char**
强制转换为const char**
(连同没有超载)这一事实解释了C,但我不知道会发生什么错误的C ++重载:
long strtol(const char*, const char**, int);
答案 2 :(得分:1)
第一个参数的'const char *'表示strtol()
不会修改字符串。
您对返回的指针所做的就是您的业务。
是的,它可以被视为类型安全违规; C ++可能会做不同的事情(但据我所知,ISO / IEC 14882:1998使用与C中相同的签名定义<cstdlib>
。)
答案 3 :(得分:1)
我有一个编译器,在C ++模式下编译时提供:
extern "C" {
long int strtol(const char *nptr, const char **endptr, int base);
long int strtol(char *nptr, char **endptr, int base);
}
显然这些都解析为相同的链接时符号。
编辑:根据C ++标准,此标头不应编译。我猜测编译器根本没有检查这个。事实上,这些定义确实在系统头文件中显示为。