IF 的奇怪结果 [英] weird results with IF

查看:30
本文介绍了IF 的奇怪结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

受到这个问题及其答案的启发,我做了一些测试.一个答案表明,数字太大(超过 32 位整数)并且它们被截断,但这并不能解释结果.同样显然它不会将双方作为字符串进行比较(正如我所期望的那样).似乎 if 感到困惑并认为好吧,我不知道 - 给它一个 TRUE".(使用 neq, gtr, lss 而不是 equ, geq, >leq 总是给 FALSE).

Inspired by this question and it's answers, I did some testing. One answer suggests, the numbers are too big (out of 32bit integer) and they get truncated, but this doesn't explain the results. Also obviously it doesn't compare both sides as strings (as I would have expected). It seems that if gets confused and thinks "well, I don't know - give it a TRUE". (Using neq, gtr, lss instead of equ, geq, leq always give FALSE).

如果 a 和/或 b 中的任何一个在 32 位整数的边界内或包含 [0-9] 之外的任何字符,则代码按预期工作.

The code works as expected, if any of a and/or b are within the borders of 32bit integer or contain any char out of [0-9].

@echo off
set a=333333333333
set b=444444444444
call :compare
set b=222222222222
call :compare
goto :eof

:compare
echo comparing %a% with %b%
if %a% geq %b% (echo a ^>= b) else (echo -)
if %b% geq %a% (echo b ^>= a) else (echo -)
if %a% leq %b% (echo a ^<= b) else (echo -)
if %b% leq %a% (echo b ^<= a) else (echo -)
if %a% equ %b% (echo a  = b) else (echo -)
if %a% == %b% (echo a == b) else (echo -)

对此是否有任何合乎逻辑的解释,或者这只是我们不得不不假思索地接受的东西?

Is there any logical explanation for this, or is it just something we have to live with without thinking?

推荐答案

这个结果的原因可以在strtol 首先使用比较运算符EQUNEQLSSLEQGTRGEQ 如我在 上的回答中所述相当于 Windows 批处理文件中的 NEQ、LSS、GTR 等符号.

The reason for this result can be found in documentation of function strtol which is used first on using the comparison operators EQU, NEQ, LSS, LEQ, GTR, GEQ as explained in my answer on Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files.

返回值
成功时,该函数将转换后的整数作为 long int 值返回.
如果无法执行有效转换,则返回零值 (0L).
如果读取的值超出 long int 可表示值的范围,则函数返回 LONG_MAX 或 LONG_MIN(在 <climits>),并且 errno 设置为 ERANGE.

Return Value
On success, the function returns the converted integral number as a long int value.
If no valid conversion could be performed, a zero value is returned (0L).
If the value read is out of the range of representable values by a long int, the function returns LONG_MAX or LONG_MIN (defined in <climits>), and errno is set to ERANGE.

最后一句在这里最重要.

The last sentence is most important here.

看起来cmd.exe中的IF的编码类似于这个C代码:

It looks like IF in cmd.exe is coded similar to this C code:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (int argc, char* argv[])
{
    const char csNo[] =  "no";
    const char csYes[] = "yes";

    char* pcEndValue1;
    char* pcEndValue2;
    int   iExitCode = 2;
    int   iErrorNumber1;
    int   iErrorNumber2;
    int   iStringResult1;
    int   iStringResult2;
    long  lIntegerValue1;
    long  lIntegerValue2;

    if(argc > 2)
    {
        /* Convert the two arguments to 32-bit signed integers. */
        lIntegerValue1 = strtol(argv[1],&pcEndValue1,0);
        iErrorNumber1 = errno;
        lIntegerValue2 = strtol(argv[2],&pcEndValue2,0);
        iErrorNumber2 = errno;

        /* Failed the conversion for any of the two arguments? */
        if(((lIntegerValue1 == 0) && (*pcEndValue1 != '')) ||
           ((lIntegerValue2 == 0) && (*pcEndValue2 != '')))
        {
            /* Compare case-sensitive the two arguments as strings. */
            iStringResult1 = strcmp(argv[1],argv[2]);
            iStringResult2 = strcmp(argv[2],argv[1]);

            printf("String comparing %s (a) with %s (b):

",argv[1],argv[2]);
            printf("a GEQ b: %s
",(iStringResult1 >= 0) ? csYes : csNo);
            printf("b GEQ a: %s
",(iStringResult2 >= 0) ? csYes : csNo);
            printf("a LEQ b: %s
",(iStringResult1 <= 0) ? csYes : csNo);
            printf("b LEQ a: %s
",(iStringResult2 <= 0) ? csYes : csNo);
            printf("a EQU b: %s
",(iStringResult2 == 0) ? csYes : csNo);
            iExitCode = 1;
        }
        else
        {
            /* Compare the values. */
            printf("Value comparing %s/%ld (a) with %s/%ld (b):

",argv[1],lIntegerValue1,argv[2],lIntegerValue2);
            printf("a GEQ b: %s
",(lIntegerValue1 >= lIntegerValue2) ? csYes : csNo);
            printf("b GEQ a: %s
",(lIntegerValue2 >= lIntegerValue1) ? csYes : csNo);
            printf("a LEQ b: %s
",(lIntegerValue1 <= lIntegerValue2) ? csYes : csNo);
            printf("b LEQ a: %s
",(lIntegerValue2 <= lIntegerValue1) ? csYes : csNo);
            printf("a EQU b: %s
",(lIntegerValue2 == lIntegerValue1) ? csYes : csNo);
            iExitCode = 0;
        }
        printf("
Error number a: %d ... %s
",iErrorNumber1,strerror(iErrorNumber1));
        printf("Error number b: %d ... %s
",iErrorNumber2,strerror(iErrorNumber2));
    }
    return iExitCode;
}

将此 C 代码编译为控制台应用程序并运行带有参数 333333333333 444444444444 的可执行文件,例如输出:

Compiling this C code as console application and running the executable with the parameters 333333333333 444444444444 results for example in output:

Value comparing 333333333333/2147483647 (a) with 444444444444/2147483647 (b):

a GEQ b: yes
b GEQ a: yes
a LEQ b: yes
b LEQ a: yes
a EQU b: yes

Error number a: 2 ... Output of function out of range (ERANGE)
Error number b: 2 ... Output of function out of range (ERANGE)

并运行带有参数 333333333333 222222222222 的可执行文件,例如输出:

And running the executable with the parameters 333333333333 222222222222 results for example in output:

Value comparing 333333333333/2147483647 (a) with 222222222222/2147483647 (b):

a GEQ b: yes
b GEQ a: yes
a LEQ b: yes
b LEQ a: yes
a EQU b: yes

Error number a: 2 ... Output of function out of range (ERANGE)
Error number b: 2 ... Output of function out of range (ERANGE)

注意:错误编号和相应的错误字符串可能因使用的 C 编译器和标准库而异.

Note: The error number and the corresponding error string can differ depending on used C compiler respectively standard library.

在两个测试用例中,两个参数都导致了从字符串到长整型转换时的 32 位有符号整数溢出.因此 strtol 返回所有四个值 LONG_MAX 并将 errno 设置为 ERANGE.但是溢出条件不是通过cmd.exe中的IF代码来判断的.它只是检查转换结果以及结束指针指向两个参数的字符,就像上面的 C 代码一样.

In both test cases both arguments resulted in a 32-bit signed integer overflow on conversion from string to long int. Therefore strtol returned for all four values LONG_MAX and set errno to ERANGE. But the overflow condition is not evaluated by code of IF in cmd.exe. It is just checked the conversion result and on which character the end pointer points to for both arguments like by the C code above.

换句话说IF处理比较运算符EQUNEQLSS的使用LEQGTRGEQ 总是整数比较,只要从字符串到整数的转换不会因为两个参数中的任何一个而失败,因为在参数字符串.超出范围条件不是 IF 不进行整数比较的理由.

In other words IF processes on usage of comparison operators EQU, NEQ, LSS, LEQ, GTR, GEQ always an integer comparison as long as conversion from string to integer does not fail for any of the two arguments because of an invalid character in argument strings. An out of range condition is no reason for IF not doing an integer comparison.

仅当两个参数字符串之一包含整数的无效字符时才进行字符串比较.

A string comparison is done only if one of the two argument strings contains an invalid character for an integer.

这篇关于IF 的奇怪结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆