是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 ++标准,此标头不应编译。 我猜测编译器根本没有检查这个。 事实上,这些定义在系统头文件中显示为此。