你如何在const-correctness下实现strtol?

根据http://www.cplusplus.com/reference/cstdlib/strtol/,此函数具有long int strtol (const char* str, char** endptr, int base)的签名。

我想知道,如果它传递一个const char *到字符串的开头,它如何设法将其转换为一个非const指针指向第一个未处理的字符而不作弊? strtol的实现看起来不会执行const_cast会是什么?

你如何在const-correctness下实现strtol

你没有,因为strtol的定义本质上不是const -correct。

这是C标准库中的一个缺陷。

有几个标准函数采用const char*参数(期望指向字符数组的开头)并返回一个非const char*指针,可用于修改该数组。

strchr就是一个例子:

 char *strchr(const char *s, int c); 

例如:

 #include  int main(void) { const char *s = "hello"; char *ptr = strchr(s, 'h'); *ptr = 'H'; } 

该程序具有未定义的行为。 在我的系统上,它会因为分段错误而死亡。

strchr本身不会出现这个问题。 它承诺不会修改传递给它的字符串,但它不会。 但它返回一个指针,然后调用者可以使用它来修改它。

早在20世纪80年代后期,ANSI C委员会可以将每个这样的函数分成两个版本,一个用于const字符数组,另一个用于非const数组:

 char *strchr(char *s, int c); const char *strcchr(const char *s, int c); 

但这会破坏现有的ANSI之前的代码,在const存在之前编写。 这与C没有使字符串文字为const原因相同。

inheritanceC大部分标准库的C ++通过提供某些函数的重载版本来处理这个问题。

最重要的是,作为C程序员,您负责不修改您定义为const对象。 在大多数情况下,该语言可以帮助您实施此function,但并非总是如此。

至于这些函数如何设法将非const指针返回到const数据,它们可能只是在内部使用const_cast (不是const_cast ,它只存在于C ++中)。 这是假设它们是用C实现的,这可能是但不是必需的。

很可能它只是使用铸造。

有许多函数在标准库中具有相同的属性。 牺牲类型安全性而非简单性是可能的原因,因为您不能像在C ++中那样重载函数。

他们期望程序员负责,并且如果str是例如字符串文字,则不编辑endptr

凭借其有限的类型系统,C是实用人员的实用语言。

strtol会做一个const_cast (或等价的)。 抛出一个const不是问题,使用结果指针修改原始const指针可能。

但是strtol只是将这个指针返回给你,而不是篡改它,所以一切都很好。

你如何在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 

下面的实现将是相同的,因为仅需要保留function签名。 由于这与strtol()不同,因此应该调用其他内容,例如strtol_s()

 #include  #include  #include  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