2011-11-23 109 views
2

我在这里面临的主要问题是strtoll()在VC 2010(error C3861: 'strtoll': identifier not found)中被标记为错误。如果我用strtol()替换它,它会做同样的事情吗?以下C代码有什么问题?

unsigned int get_uintval_from_arg(int argc, int index, char **argv, 
            unsigned int lower_bound, unsigned int upper_bound) 
{ 
    unsigned int return_val=0; 

    if (index + 1 <= argc - 1) 
    { 
     return_val=(unsigned int)strtoll(argv[index+1],NULL,10); 
     if (errno == EINVAL || errno== ERANGE) 
     { 
      fprintf(stderr, "Could not parse argument %s for switch %s!\n", 
        argv[index], argv[index+1]); 
      return 0; 
     } 
    } 
    // ....... I will post the remaining part of the code if necessary 
    ....... 
} 
+1

您是否在程序中包含'#include '?由于“long long”比“unsigned long”长很多,为什么你要使用'long long'变种? – sarnold

+0

是的,我已经包含了 John

+2

'long long'是最新的ISO 9899:99 C标准,“C99”的一部分,它不被Microsoft支持。 Visual Studio只支持自1990年以来的二十一年C标准。 – Lundin

回答

5

由于您的return_valunsigned int,你或许应该使用strtoul() C89以来这一直是标准,因此被MSVC(而strtoll()只因为C99作为标准的,而不是由MSVC支持)的支持。

您对错误条件的测试是不够的。在调用转换函数之前,您需要将errno设置为零;您还需要检测是否报告了错误,这比看起来更棘手。

科§7.20.1.4 '的与strtol,与strtoll,strtoul将和strtoull将功能' C99标准说:

返回

strtolstrtollstrtoulstrtoull功能返回已转换的 值(如果有)。如果不能执行转换,则返回零。如果正确的值 超出了可表示值的范围,则返回LONG_MIN,LONG_MAX,LLONG_MIN, LLONG_MAX,ULONG_MAX或ULLONG_MAX(根据返回类型 以及值的符号(如果有))以及宏ERANGE存储在errno

您也可以阅读一下存储在endptr参数转换函数来告诉未进行转换的价值(而不是一个有效的零转变)。

如果主题序列为空或者没有预期的格式,则不会执行任何转换;请参阅 。 nptr的值存储在由endptr指向的对象中,提供的 表示endptr不是空指针。

所以,你必须更多像这样的编写代码(省略对EINVAL的测试,因为标准没有提到这些功能设置errno到EINVAL):

unsigned int return_val=0; 

if (index + 1 <= argc - 1) 
{ 
    char *end; 
    unsigned long ul; 
    errno = 0; 
    ul = strtoul(argv[index+1], &end, 10); 
    if ((ul == 0 && end == argv[index+1]) || 
     (ul == ULONG_MAX && errno == ERANGE) || 
     (ul > UINT_MAX)) 
    { 
     fprintf(stderr, "Could not parse argument %s for switch %s!\n", 
       argv[index], argv[index+1]); 
     return 0; 
    } 
    retval = (unsigned int)ul; 
} 

注意,这是比测试更简单对于有符号整数转换,必须考虑负极限<type>_MIN以及<type>_MAX限制。

另请注意,您应该将结果记录在unsigned long中,然后检查它是否符合您指定的范围,该范围可能限于UINT_MAX(在类Unix的64位环境中可能小于ULONG_MAX) 。

+0

'errno = ERANGE' ?? :) – bdonlan

+0

也应该检查'retval> UINT_MAX'(在向下转换为'unsigned int'之前),以防它在64位长的平台上。 – bdonlan

+0

@bdonlan:是的 - 谢谢(对两个评论)。我修正了最后一段没有看到你的评论的沮丧(但第一版的答案没有包括这一点,并且你的评论是真实的)。我错过了'='而不是'=='错字(但编译器会在我编译代码时警告过我)。 –

1

在Visual Studio中使用_strtoi64()方法代替。它具有与strtoll相同的参数。

为了兼容,你可以简单地用一个定义来包装它与strtoll(如果你需要的可移植性),如

#if defined(_MSC_VER) 
#define strtoll _strtoi64 
#endif 
+2

这可能工作,但它不可移植。 –

+0

@PaulR是的,他特别说VS。如果他希望它是可移植的,他应该使用define来将_strtoi64重新定义为microsoft c编译器的strtoll。 –

+0

@bdonlan是的,我后来注意到,因为我有问题,先将一些代码移植到VS C编译器之前,我忽略了他在做什么,只是告诉他为什么strtoll不工作。 –

0

strtol()是一个long适当的库函数。为便于携带,请将return_val声明为long或unsigned long。如果是后者,请查看MSVC是否提供strtoul()

+0

是的,他使用漫长的长整型int,但是转换为unsigned int ...我有点跳过那个。 –

+0

如果'long'和'int'的大小相同,这是解析'INT_MAX + 1..UINT_MAX'之间的值的合理方法。 – bdonlan

+0

@bdonlan:假设'long'和'int'是相同的大小是短视的。它的写法非常简单和容易:应该强调的是,不要采用环境敏感的懒惰快捷方式,当它最终打破时很容易花费大量时间。 – wallyk

0

你的目的,你应该使用strtoul,因为你是转换为unsigned long类型,而不是一个signed long long类型(这是什么strtoll会做)。如果您需要阅读long long,请使用Microsoft特定的_strtoi64;您可以使用#define在Microsoft平台上将其重命名为strtoll,或者在Windows特定的可移植性垫片文件(在私有头文件中使用您自己的原型)中编写包装函数。