提问人:user102008 提问时间:6/15/2009 更新时间:6/15/2009 访问量:6337
strtol,strtod不安全吗?
Are strtol, strtod unsafe?
问:
似乎并有效地允许(并迫使)你抛弃字符串中的恒常性:strtol()
strtod()
#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 *
答:
第一个参数的“const char *”表示不会修改字符串。strtol()
你对返回的指针做什么是你的事。
是的,它可以被视为类型安全违规行为;C++可能会以不同的方式做事(尽管据我所知,ISO/IEC 14882:1998使用与C相同的签名进行定义)。<cstdlib>
评论
我猜是因为替代方案更糟。假设将原型更改为添加: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
但是,当我们尝试编译此代码时会发生什么?编译器错误!这很不直观,但您不能隐式地将 a 转换为 .请参阅 C++ FAQ Lite 以获取原因的详细说明。从技术上讲,它在那里谈论的是 C++,但这些参数对 C 同样有效。在 C/C++ 中,只允许您在最高级别隐式地从“指向类型的指针”转换为“指向类型的指针”:您可以执行的转换是从 到 ,或者等效地从“指针到(指针)”到“指针(指针)”。char **
const char **
const
char **
char * const *
char
const
char
由于我猜解析非常量字符串比解析常量字符串的可能性要大得多,因此我继续假设不太可能的情况的不正确性比使常见情况成为编译器错误更可取。const
评论
long int strtol(char *nptr, char **endptr, int base);
long int strtol(const char *nptr, const char **endptr, int base);
strchr
strstr
const
char **
的函数? 而不是 C++ FAQ,尽管我并不完全相信这些解释很容易理解。
是的,其他函数也有同样的“持续洗钱”问题(例如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 正确版本,所以你会得到 const-incorrect 的折衷。
C++ 没有提到 strtol 和 strtod 的类似重载,事实上我的编译器 (GCC) 也没有它们。我不知道为什么不:你不能隐式转换为(加上没有重载)这一事实解释了 C 的情况,但我不太明白 C++ 重载有什么问题:char**
const char**
long strtol(const char*, const char**, int);
评论
我有一个编译器,在 C++ 模式下编译时提供:
extern "C" {
long int strtol(const char *nptr, const char **endptr, int base);
long int strtol(char *nptr, char **endptr, int base);
}
显然,这两者都解析为相同的链接时间符号。
编辑:根据 C++ 标准,此标头不应编译。我猜编译器根本没有检查这一点。事实上,这些定义在系统头文件中确实是这样显示的。
评论