[英]C - Strange behavior with a post-increment on isdigit() call inside while loop
我有一个简单的程序,带有一个函数来检查C字符串是否只有整数,是否返回true (1)
或false (0)
:
#include <ctype.h>
#include <stdio.h>
#include <stdbool.h>
bool isStrWholeNumber(const unsigned char *s) {
if (*s == '\0') return false;
while (isdigit(*s++));
if (*s == '\0') return true;
return false;
}
int main()
{
unsigned char str[] = "a";
bool b = isStrWholeNumber(str);
printf("%d\n", b);
return 0;
}
指针增量*s++
应该在增量之前将值传递给isdigit
函数,但是似乎它在增量之后传递值,因此它传递字符'\\ 0'而不是'a',因为该函数返回的是true。
更改函数以将指针增加到函数调用之外,可以正常工作,并为字符“ a”返回false:
bool isStrWholeNumber(const unsigned char *s) {
if (*s == '\0') return false;
while (isdigit(*s)) s++;
if (*s == '\0') return true;
return false;
}
为什么是while (isdigit(*s++));
不工作吗?
这是当您累了或睡不好时会发生的事情,最终您会犯此类错误。 如您在答案中所见,该程序运行正常。
经过一番休息后,我回到了这个功能,并取得了不错的效果,既快又小。 我使用了GCC分析器和gprof来测试性能,还检查了程序集的性能和代码大小。 在有和没有GCC优化-O3的情况下进行了测试。
这是带注释的结果,因此您可以理解:
bool isStrWholeNumber(const unsigned char *s) {
if (*s) { // Check if string is not empty
--s; // Decrement pointer. It will be incremented in while bellow
while (isdigit(*++s)); // Iterate over string until a non digit character is found
return !*s; // Returns 1 if end of string was reached, else, return 0
}
return false; // Always returns false if string is empty
}
可能可以进一步优化此功能,但我不知道如何。
由于易读性差,许多不好的代码都考虑使用此功能,请不要在任何地方使用它。
程序运行正常。 在第一个代码中, isdigit(*s++)
将返回0
并且s
将递增,并且if (*s == '\\0') return true;
的语句if (*s == '\\0') return true;
将返回true
。
在第二个代码段中,将不评估*s++
并且该语句return false;
将返回false
。
正如@haccks所解释的,该程序的行为符合预期。 无论isdigit
的结果如何,您总是在递增s
。 这就是为什么您应该始终为清楚起见而不是为了简洁而写的原因。 对您的程序进行的微小修改使其可以执行您想要的操作,并使它更加清晰:
bool isStrWholeNumber(const unsigned char *s) {
if (*s == '\0') return false;
while (isdigit(*s))
++s;
if (*s == '\0') return true;
return false;
}
您的原始程序依赖于:
++
运算符优先于*
运算符,因此我们不会意外增加指针的内容。 ++
在增加指针之前返回该值,因此我们将获得正确的指针值。 isdigit
将获取取消引用的值。 在一行代码中发生了如此多的事情,它没有按您预期的那样表现是否令人惊讶?
顺便说一句,如果您没有得到正确终止的字符串,您的代码就是段访问冲突。
对于第一个版本,增量是无条件执行的。 因此,无论测试是否失败,指针都会递增,因此它始终指向下一个字符。 如果由于*s
为NUL( '\\0'
)而导致测试失败,则它仍将增加1。 if
访问的字符超过了终止符,则以下内容将if
访问,如果数组不够大,则该行为是未定义的行为 。 但是,当您访问字符串的末尾时,绝对不是必需的 。
如果像第二个版本那样将增量放入循环主体中,则只有在测试为true while
,增量才会递增。 这就是想要的行为(据我从函数名称中看到的那样)。
注意:您无需取消引用指针即可递增。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.