是strtol,strtod不安全吗?

时间:2009-06-14 20:36:01

标签: c const std c-strings const-char

似乎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 *,因此强制类型中的不安全更改。)这不是真的很危险吗?

4 个答案:

答案 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 “:您可以执行的转换是从constchar **,或等效于”指向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 ++标准,此标头不应编译。我猜测编译器根本没有检查这个。事实上,这些定义确实在系统头文件中显示为。