繁体   English   中英

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

[英]How do you implement strtol under const-correctness?

根据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 <string.h>
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原因相同。

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

底线是, 作为一个C程序员,有责任不修改您定义为对象const 在大多数情况下,该语言可以帮助您强制执行此操作,但并非总是如此。

至于这些函数如何设法将非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

下面的实现将是相同的,因为仅需要保留功能签名。 由于这与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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM