根据http://www.cplusplus.com/reference/cstdlib/strtol/,此功能的签名为a
。
我想知道:如果它被传递给long int strtol (const char* str, char** endptr, int base)
到字符串的开头,它如何设法将其变成一个非const指针指向第一个未经处理的字符而不作弊?什么是strtol的实现看起来不会执行const_cast?
答案 0 :(得分:5)
如何在const-correctness下实现
strtol
?
你没有,因为strtol
的定义本质上不是const
- 正确。
这是C标准库中的一个缺陷。
有几个标准函数采用const char*
参数(预期指向字符数组的开头)并返回一个非const
char*
指针,可用于修改那个数组。
strchr
就是一个例子:
char *strchr(const char *s, int c);
例如:
#include <string.h>
int main(void) {
const char *s = "hello";
char *ptr = strchr(s, 'h');
*ptr = 'H';
}
此程序具有未定义的行为。在我的系统上,它会因分段错误而死亡。
问题不会发生在strchr
本身。它承诺不会修改传递给它的字符串,但它不会。但它返回一个指针,然后调用者可以使用它来修改它。
ANSI C委员会,在20世纪80年代后期,可以将每个这样的函数分成两个版本,一个作用于const
字符数组,另一个作用于非{{1数组:
const
但这会破坏在char *strchr(char *s, int c);
const char *strcchr(const char *s, int c);
存在之前编写的现有ANSI前代码。这与C没有创建字符串文字const
的原因相同。
继承C大部分标准库的C ++通过提供某些函数的重载版本来解决这个问题。
底线是你,作为C程序员,负责不修改你定义为const
的对象。在大多数情况下,该语言可以帮助您强制执行此操作,但并非总是如此。
至于这些函数如何设法返回非const
指向const
数据的指针,它们可能只是在内部使用强制转换(不是const
,只存在于C ++中) 。这是假设它们是用C实现的,这可能但不是必需的。
答案 1 :(得分:2)
最有可能只是使用铸造。
有许多函数在标准库中具有相同的属性。牺牲类型安全性而不是简单性是可能的原因,因为你不能像在C ++中那样重载函数。
他们希望程序员负责,如果endptr
是{1}},则不会编辑str
。
凭借它的有限类型系统,C是实用人士的实用语言。
答案 2 :(得分:1)
strtol
确实做了const_cast
(或等效)。转换const
不是问题,使用结果指针修改原来的const
指针可能是。
但是strtol
只是将这个指针返回给你而不会篡改它,所以一切都很好。
答案 3 :(得分:1)
如何在const-correctness下实现strtol?
使用C11 _Generic
将允许代码调用
// when passed argument for `str` is `char *` and for `endptr` is `char **`
long strotol(const char* str, char** endptr, int base);
// or
// when passed argument for `str` is `const char *` and for `endptr` is `const char **`
long strotol_c(const char* str, const char** endptr, int base);
// and warn/error otherwise
实现,如下所示,只需要保留功能签名即可。由于这与strtol()
不同,因此应该将其称为其他内容,例如strtol_s()
。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long int strtol_c(const char * restrict nptr, const char ** restrict endptr, int base) {
return strtol((char *) nptr, (char **) endptr, base);
}
#define strtol_s(n,e,b) _Generic(n, \
char *: strtol((n), (e), (b)), \
const char *: strtol_c((n), (e), (b)), \
default: 0 \
)
int main(void) {
char *src = malloc(100);
strcpy(src, "456");
const char *srcc = "123";
char *endptr;
const char *endcptr;
long L[6] = { 0 };
// OK - matching str and *endptr
L[0] = strtol_s(src, &endptr, 0);
// warning: passing argument 2 of 'strtol' from incompatible pointer type
L[1] = strtol_s(src, &endcptr, 0);
// warning: passing argument 2 of 'strtol_c' from incompatible pointer type
L[2] = strtol_s(srcc, &endptr, 0);
// OK - matching str and *endptr
L[3] = strtol_s(srcc, &endcptr, 0);
L[4] = strtol(src, &endptr, 0);
// warning passing argument 2 of 'strtol' from incompatible pointer type
// OK
L[5] = strtol(src, &endcptr, 0);
return !L[0];
}
丢失的内容:strtol_s()
不是真正的函数,因此无法指向它。
如何将其转换为指向第一个未处理角色的非const指针而不作弊?
strtol()
,虽然它需要char **endptr
作为第二个参数,但不会修改*endptr
。