17

似乎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()基本上将 myconst char *放入一个char *for me 中,没有任何警告或任何东西。(事实上​​,它不允许你键入baras a const char *,因此会强制进行不安全的类型更改。)这不是很危险吗?

4

4 回答 4

14

我猜是因为替代方案更糟。假设原型被更改为添加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 转换char **为 a const char **。有关原因的详细说明,请参阅C++ FAQ Lite 。它在技术上谈论 C++,但参数对 C 同样有效。在 C/C++ 中,您只能在最高级别隐式转换从“类型指针”到“类型指针”:您可以进行const 转换perform 是从char **to char * const *,或等效地从“pointer to (pointer to char)”到“pointer to ( constpointer to char)”。

因为我猜想解析非常量字符串比解析常量字符串更有可能,所以我继续假设,const对于不太可能的情况,-incorrectness 比使常见情况成为编译器错误更可取。

于 2009-06-14T21:02:30.510 回答
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 正确版本,因此您会得到 const 不正确的折衷方案。

C++ 没有提到 strtol 和 strtod 的类似重载,实际上我的编译器 (GCC) 没有它们。我不知道为什么不:你不能隐式char**转换为const char**(以及没有重载)这一事实为 C 解释了它,但我不太明白 C++ 重载会出现什么问题:

long strtol(const char*, const char**, int);
于 2009-06-15T00:53:46.260 回答
1

第一个参数的 'const char *' 表示strtol()不会修改字符串。

你用返回的指针做什么是你的事。

是的,它可以被视为类型安全违规;C++ 可能会做不同的事情(不过,据我所知,ISO/IEC 14882:1998 定义<cstdlib>的签名与 C 中的签名相同)。

于 2009-06-14T20:41:16.770 回答
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++ 标准,这个头文件不应该编译。我猜编译器根本没有检查这个。事实上,这些定义在系统头文件中确实如此。

于 2009-06-15T01:00:03.327 回答