是strtol,strtod不安全吗?
似乎strtol()
和strtod()
有效地允许(并强制)你在字符串中抛弃constness:
#include #include 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 *
,因此强制类型中的不安全更改。)这不是真的很危险吗?
我猜这是因为替代方案更糟糕。 假设原型已更改为添加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 ++中,你只允许在最高级别从“指针类型 ”隐式转换为“指向const
类型的指针”:转换你可以执行从char **
到char * const *
,或等效地从“指向(指向char
指针)”到“指向(指向char
const
指针)”的指针。
因为我猜想解析一个非常量字符串比解析一个常量字符串更有可能,我会继续假设对于不太可能的情况, const
notorrectness比使常见情况成为编译器错误更可取。
是的,其他函数具有相同的“常量清洗”问题(例如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-incorrect的妥协。
C ++没有提到strtol和strtod的类似重载,实际上我的编译器(GCC)没有它们。 我不知道为什么不:你不能隐式地将char**
为const char**
(连同没有重载)这个事实解释了C,但我不太清楚会出现什么问题。一个C ++重载:
long strtol(const char*, const char**, int);
第一个参数的’const char *’表示strtol()
不会修改字符串。
你用返回的指针做什么是你的事。
是的,它可以被视为类型安全违规; C ++可能会做不同的事情(但据我所知,ISO / IEC 14882:1998使用与C中相同的签名定义
)。
我有一个编译器,在C ++模式下编译时提供:
extern "C" { long int strtol(const char *nptr, const char **endptr, int base); long int strtol(char *nptr, char **endptr, int base); }
显然,这两者都解析为相同的链接时符号。
编辑:根据C ++标准,此标头不应编译。 我猜测编译器根本没有检查这个。 事实上,这些定义在系统头文件中显示为此。