strtol、strtod 不安全吗?
Posted
技术标签:
【中文标题】strtol、strtod 不安全吗?【英文标题】:Are strtol, strtod unsafe? 【发布时间】:2010-11-02 21:11:18 【问题描述】:似乎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 *
,因此会强制进行不安全的类型更改。)这不是很危险吗?
【问题讨论】:
【参考方案1】:我猜是因为替代方案更糟。假设原型改成添加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 的指针”转换为“指向 const
的指针” em>type" 在***别:您可以执行的转换是从char **
到char * const *
,或者等效地从“pointer to (pointer to char
)”到“pointer to (const
指向char
)"的指针。
由于我猜想解析非常量字符串的可能性远大于解析常量字符串,因此我会继续假设 const
-incorrectness 对于不太可能的情况比使常见情况成为编译器错误更可取.
【讨论】:
但是 C++ 不会阻止你重载函数:你可以有long int strtol(char *nptr, char **endptr, int base);
和 long int strtol(const char *nptr, const char **endptr, int base);
:这修复了你的编译错误。事实上,该标准对其他此类功能也是如此,例如strchr
和strstr
,
您可以参考 C 常见问题解答网站 What's the difference between const char *p
, char const *p
, and char * const p
?,更具体地说,Why can't I pass a char **
to a function which expects a const char **
? 而不是 C++ 常见问题解答,尽管我并不完全相信这些解释很容易理解。跨度>
【参考方案2】:
是的,其他函数也有同样的“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-incorrect 妥协。
C++ 没有提到 strtol 和 strtod 的类似重载,实际上我的编译器 (GCC) 没有它们。我不知道为什么不这样做:你不能将char**
隐式转换为const char**
(以及没有重载)这一事实为 C 解释了这一点,但我不太明白 a 会有什么问题C++ 重载:
long strtol(const char*, const char**, int);
【讨论】:
stlport 提供了这种重载(以及其他一些)。【参考方案3】:第一个参数的 'const char *' 表示 strtol()
不会修改字符串。
你对返回的指针做什么是你的事。
是的,它可以被视为类型安全违规; C++ 可能会做不同的事情(不过,据我所知,ISO/IEC 14882:1998 定义了 <cstdlib>
与 C 中的签名相同)。
【讨论】:
C++ 确实定义了 strtol(以及 cstdlib 中的所有其他内容),其签名与 C 相同,但不是 cstring 和 cwchar 中的所有内容。【参考方案4】:我有一个编译器,在 C++ 模式下编译时提供:
extern "C"
long int strtol(const char *nptr, const char **endptr, int base);
long int strtol(char *nptr, char **endptr, int base);
显然,它们都解析为相同的链接时符号。
编辑:根据 C++ 标准,此标头不应编译。我猜编译器根本没有检查这个。实际上,这些定义确实在系统头文件中显示为这样。
【讨论】:
以上是关于strtol、strtod 不安全吗?的主要内容,如果未能解决你的问题,请参考以下文章