【问题标题】:How to convert string to int64_t?如何将字符串转换为 int64_t?
【发布时间】:2013-06-04 20:59:10
【问题描述】:

如何将程序参数从argv转换为int64_tatoi() 仅适用于 32 位整数。

【问题讨论】:

  • int64_tlong 相同的平台上,那么快速的hacky 方法就是使用atol()
  • 将 sscanf 与 int64_t 的匹配说明符一起使用可以提供独立于平台的方法。
  • 有点迂腐的观点:你要问的不是如何将 char * 转换为 int64_t (如果你想要这样,一个简单的转换就是答案)而是如何转换字符串由char * 指向int64_t,它表示一些面向人类的文本约定中的数字,如十进制字符串。

标签: c unix int64


【解决方案1】:

如何将字符串转换为 int64_t?

最简单的

#include <stdlib.h>
int64_t value = atoll(some_string);  // lacks error checking.  UB on overflow

更好

long long v = strtoll(s, NULL, 0);  // No reported errors, well defined on overflow

稳健:创建一个辅助函数来检测所有问题。

#include <stdbool.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>

// Return error flag
bool my_strtoi64(int64_t *value, const char *s) {
 // Maybe add a s==NULL, value==NULL checks.

  char *endptr;
  errno = 0;
  long long v = strtoll(s, &endptr, 0);

  // Optional code for future growth of `long long`
  #if LLONG_MIN < INT64_MIN || LLONG_MAX > INT64_MAX
  if (v < INT64_MIN) {
    v = INT64_MIN;
    errno = ERANGE;
  } else if (v > INT64_MAX) {
    v = INT64_MAX;
    errno = ERANGE;
  #endif

  *value = (int64_t) v;

  if (s == endptr) { // No conversion, *v is 0
    return true;
  }
  if (errno == ERANGE) { // Out of range
    return true;
  }
  if (errno) { // Additional implementations specific errors
    return true;
  }
  while (isspace(*(unsigned char* )endptr)) { // skip trail white-space
    endptr++;
  }
  if (*endptr) { // Non-numeric trailing text
    return true;
  }
  return false; // no error
}

【讨论】:

    【解决方案2】:

    来自网络搜索的用户也应该考虑std::stoll

    对于const char*,它并没有严格回答这个原始问题,但无论如何,许多用户都会有std::string。如果您不关心效率,即使您有const char*,您也应该获得一个隐式转换(基于使用单参数std::string 构造函数的用户定义转换)到std::string

    它比std::strtoll 更简单,std::strtoll 总是需要 3 个参数。

    如果输入不是数字,它应该抛出,但请参阅these comments

    【讨论】:

    • 这是我认为 C++ 的最佳答案。
    【解决方案3】:

    这适用于我使用不同的 int64 类型,我喜欢干净的 C++ 风格:

    std::istringstream iss(argv[i]);
    int64_t i64;
    iss >> i64;
    

    你可能会得到一个编译错误:operator

    如果 argv[i] 包含“HALLO”,我不知道会发生什么。

    【讨论】:

    • 如果转换失败(如“HALLO”),你会得到 0。但失败位也会被设置,所以你应该调用 iss.fail() 来检查。
    【解决方案4】:

    符合 C99 的尝试。

    [编辑] 雇用了@R。更正

    // Note: Typical values of SCNd64 include "lld" and "ld".
    #include <inttypes.h>
    #include <stdio.h>
    
    int64_t S64(const char *s) {
      int64_t i;
      char c ;
      int scanned = sscanf(s, "%" SCNd64 "%c", &i, &c);
      if (scanned == 1) return i;
      if (scanned > 1) {
        // TBD about extra data found
        return i;
        }
      // TBD failed to scan;  
      return 0;  
    }
    
    int main(int argc, char *argv[]) {
      if (argc > 1) {
        int64_t i = S64(argv[1]);
        printf("%" SCNd64 "\n", i);
      }
      return 0;
    }
    

    【讨论】:

    • +1 表示使用sscanf 的聪明想法,但您需要的是SCNd64,而不是PRId64。我也不清楚sscanf 是否必须在溢出时表现良好。
    • @R.. 我认为 scanf() 系列被指定为像 strtol() 系列函数一样工作。在后者中,范围错误导致ERANGE 存储在errno 中。 (C11 草案 7.8.2.3.3)。所以可以合并一个errno 测试。
    • @chux 你确定吗?根据thisSCNd64scanfPRId64printf
    • @chux:我在任何地方都找不到 scanf 指定的行为方式。 scanf 的规范甚至没有说明如何存储要确定的值的任何要求。它只是指定了输入的预期格式和所需的输出类型,但没有关于转换过程。这似乎是一个疏忽,但它在错误处理方面留下了很多歧义......
    • @R.. 我建议 scanf() 家族被指定为像 strtol() 一样工作来自 C11 Draft 7.21.6.2.12: "d 匹配一个可选带符号的十进制整数,其格式与 strtol 函数的主题序列的预期格式相同,基本参数的值为 10 ..."。我的 Eclipse C Indigo Service Release 1 编译器确实通过 scanf()errno 设置为 ERANGE。所以至少有 1 个编译器这样做。尽管strtol() 设置了errno,但我和你一样,在scanf() 错误处理方面看到了歧义。也许其他人可能知道?
    【解决方案5】:

    有几种方法可以做到:

      strtoll(str, NULL, 10);
    

    这是 POSIX C99 兼容的。

    你也可以使用 strtoimax;它具有以下原型:

     strtoimax(const char *str, char **endptr, int base);
    

    这很好,因为它将始终与本地 intmax_t 一起使用...这是 C99,您需要包含 &lt;inttypes.h&gt;

    【讨论】:

    • @OliCharlesworth 是的,你是对的,但是演员表的存在是为了提醒你,如果 OP 想要解析它,他们可以用指向字符串的指针替换它。跨度>
    • @AhmedMasud 这就是文档的用途。或者也许是评论。请不要添加多余的演员表,它们是多余的,甚至可能隐藏错误,最重要的是,它们会降低可读性。
    • @Ahmed:啊,很公平。请注意,可能还值得一提的是,这种方法假定 int64_tlong long 相同。
    • @OliCharlesworth:并不认为它们是相同的,只是long long 足够大以存储int64_t 的任何值,这几乎是正确的,但并不完全正确。看我的回答。
    • 当结果在int64_t范围内时,这个方法是可以的。当结果超出int64_t 的范围时,这种方法需要未发布的额外工作来便携式检测此类问题。
    【解决方案6】:

    100% 便携地做这件事有点棘手。 long long 要求至少为 64 位,但不一定是二进制补码,因此它可能无法表示 -0x7fffffffffffffff-1,因此使用 strtoll 可能会出现问题。同样的问题也适用于strtoimax。你可以做的是消耗前导空格(如果你想允许前导空格)并首先检查符号,然后使用 strtoullstrtoumax,其中任何一个都需要支持高达完整正数范围的值int64_t。然后您可以应用该标志:

    unsigned long long x = strtoull(s, 0, 0);
    if (x > INT64_MAX || ...) goto error;
    int64_t y = negative ? -(x-1)-1 : x;
    

    编写此逻辑是为了避免所有溢出情况。

    【讨论】:

    • 但公平地说,我怀疑int64_t 是在任何具有不同于二进制补码的符号表示的系统上定义的。我也认为这是精确宽度整数类型可选的主要原因之一。
    • 我以为 POSIX 需要它,但实际上 POSIX 只需要 8、16 和 32 位精确大小的类型。 int64_tuint64_t 在 POSIX 上是可选的。所以我同意int64_t 不太可能存在于longlong long 不适合的系统上。
    • 不清楚“如何编写逻辑以避免所有溢出情况”。 -(x-1)-1-x 工作方式与 x 相同,是一个宽无符号类型。
    • @chux:我想我的意思是-((int64_t)x-1)-1。这更有意义吗?
    • -((int64_t)x-1)-1 更有意义,但(int64_t)x 仍然是有符号整数溢出。也许-1-((int64_t)-(x+1))
    【解决方案7】:

    strtoll 将其转换为 long long,通常是 64 位整数。

    【讨论】:

      猜你喜欢
      • 2011-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-31
      • 2018-04-30
      相关资源
      最近更新 更多