Rules for how CMD.EXE parses numbers

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
jeb
Expert
Posts: 917
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Rules for how CMD.EXE parses numbers

#16 Post by jeb » 20 Sep 2013 02:23

penpen wrote:This behaviour is a hint, that the command line interpreter has an internal representation
for 32 bit signed integer numbers (sint32) of the following form (minimum):
- 1 bit sign
- 32 bit unsigned integer number (uint32) value


I don't think so.

I test with

Code: Select all

for /L %%M in (2147483645 1 2147483647) do (echo %%M & pause)

And I got
output wrote:2147483645
2147483646
2147483647
-2147483648
-2147483647
-2147483646
-2147483645
-2147483644
...

The problem seems to be the comparision inside the FOR.

I suppose the internal pseudocode looks like this

Code: Select all

for (counter=startNum; counter <= endNumber; counter++)
{
  doThe_DoBlock();
}



---------
cmderror wrote:• Set /A 3000000000
XP : -1294967296
7 : overflow

(I would bet the behavior discrepancy was introduced with Vista, but I don't have any Vista box at hand to confirm)

Yes, Vista seems to work here like Win7.

Code: Select all

Set /A 3000000000
XP : -1294967296
vista/32: overflow
7 : overflow


jeb

penpen
Expert
Posts: 1725
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Rules for how CMD.EXE parses numbers

#17 Post by penpen » 20 Sep 2013 10:00

jeb wrote:I suppose the internal pseudocode looks like this

Code: Select all

for (counter=startNum; counter <= endNumber; counter++)
{
  doThe_DoBlock();
}

I have thought about that, before i wrote my post, but have discarded it, i should have explained my thoughts in my above post directly (my fault not to do this):
npocmaka_ wrote:

Code: Select all

for /l %%M in (2147483647  1 2147483648) do ( echo %%M & pause )

would not produce an endless loop, as it would be this in pseudocode (2147483648==-2147483648):

Code: Select all

for (counter=2147483647; counter <=-2147483648; counter++)
{
  doThe_DoBlock();
}

The only possibility to get these results is, that the following inequalties are true:
counter <= 2147483648, counter in { -2147483648, 2147483647 } (*)

Additionally, if you use an upper bound of 2147483647, you also get an endless loop, so these inequalties are true, too:
counter <= 2147483647, counter in { -2147483648, 2147483647 } (**)

You could say: Who knows if it is overflowing, or set to the upper bound?
This is done for the first value of the for /L loop (but only with the next example):

Code: Select all

Z:\>for /l %M in (2147483648  1 2147483648) do ( echo %M & pause )

Z:\>(echo 2147483647   & pause  )
2147483647
Drücken Sie eine beliebige Taste . . .

Z:\>(echo -2147483648   & pause  )
-2147483648
Drücken Sie eine beliebige Taste . . .

Z:\>(echo -2147483648   & pause  )
-2147483647
Drücken Sie eine beliebige Taste . . .

Z:\>(echo -2147483648   & pause  )
-2147483647
Drücken Sie eine beliebige Taste . . .

[... endless loop]
So it seems you are right, but then i had tested these examples:

Code: Select all

for /l %M in (2147483646  1 0x80000000) do ( echo %M & pause )
for /l %M in (2147483646  1 -0x80000000) do ( echo %M & pause )
The upper one is an endless loop, while the lower one produces no output.
So 0x80000000 != -0x80000000 (***), although these numbers should be equal according to set /A, and the normal 'behavior' of int32.
Looking at the decimal values only the following can be derived from (*), (**), and (***):
counter <= 2147483647 < 2147483648, counter in { -2147483648, 2147483647 } (*)

I should have added that to my prior post, but i had not much time, so i'd shortened the above post.

And my formulation "This behaviour is a hint, that..." should make clear that there is (at minimum) one additional possibility to explain the behavior:
It may be, that the internal representation of these numbers is done in long int ((s/u)int64) Format, but as WinXP is 32 bit and the processors it is designed for have no native long support, i think there are just 2 values in use.

penpen

jeb
Expert
Posts: 917
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Rules for how CMD.EXE parses numbers

#18 Post by jeb » 20 Sep 2013 11:36

penpen wrote:So it seems you are right, but then i had tested these examples:

I still asume I'm right :)

I tested too with hex-values, first I'm confused of the tests

Code: Select all

for /l %M in (-2  1 0xffffffff) do @( echo %M & pause >nul )


I assumed only to get -2 and -1, but it's endless :?:
I made many tests that are all confused me, until I move the hex value to the front :idea:

Code: Select all

for /l %M in (0xffffffff 1 0xffffffff) do @( echo %M & pause >nul )
for /l %M in (0xffff0000 1 0xffffffff) do @( echo %M & pause >nul )
for /l %M in (0x80000000 1 0xffffffff) do @( echo %M & pause >nul )


All results in the same output :!:
Output wrote:2147483647
-2147483648
-2147483647
-2147483646
...

So the FOR /L parses hex values quite different than SET /a.

All values greater/equal 0x80000000 are set to 2147483647.

So my pseudo code still stands.

jeb

dbenham
Expert
Posts: 2288
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Rules for how CMD.EXE parses numbers

#19 Post by dbenham » 20 Sep 2013 11:59

penpen wrote:
jeb wrote:I suppose the internal pseudocode looks like this

Code: Select all

for (counter=startNum; counter <= endNumber; counter++)
{
  doThe_DoBlock();
}

I have thought about that, before i wrote my post, but have discarded it, i should have explained my thoughts in my above post directly (my fault not to do this):
npocmaka_ wrote:

Code: Select all

for /l %%M in (2147483647  1 2147483648) do ( echo %%M & pause )

would not produce an endless loop, as it would be this in pseudocode (2147483648==-2147483648):

Code: Select all

for (counter=2147483647; counter <=-2147483648; counter++)
{
  doThe_DoBlock();
}

The only possibility to get these results is, that the following inequalties are true:
counter <= 2147483648, counter in { -2147483648, 2147483647 } (*)

I disagree with penpen and agree with jeb. Penpen is assuming FOR /L uses the same parsing rules as SET /A. You must remember that SET /A has its own rules that differ from all the other contexts.

I believe FOR /L is using the same parsing rules that I outlined for the IF command:
dbenham wrote:All three numeric notations employ a similar strategy: First ignore any leading negative sign and convert the number into an unsigned binary representation. Then apply any leading negative sign by taking the 2's compliment.

The big difference (from SET /A) is that overflow conditions no longer result in an error. Instead the maximum magnitude value is used. A positive overflow becomes 2147483647, and a negative overflow becomes -2147483648.

Here is my proof:

Code: Select all

C:\test>for /L %N in (999999999999999 -1 2147483645) do @echo %N
2147483647
2147483646
2147483645

C:\test>for /L %N in (-999999999999999 1 -2147483645) do @echo %N
-2147483648
-2147483647
-2147483646
-2147483645

C:\test>for /L %N in (0xFFFFFFFFFFFFF -1 0x7FFFFFFD) do @echo %N
2147483647
2147483646
2147483645

C:\test>for /L %N in (-0xFFFFFFFFFFFFF 1 -0x7FFFFFFD) do @echo %N
-2147483648
-2147483647
-2147483646
-2147483645

C:\test>for /L %N in (07777777777777777777777777 -1 017777777775) do @echo %N
2147483647
2147483646
2147483645

C:\test>for /L %N in (-07777777777777777777777777 1 -017777777775) do @echo %N
-2147483648
-2147483647
-2147483646
-2147483645

I don't know how I missed FOR /L and EXIT [/B] in my original post. I need to edit that original post with the new info :!:

Both a max end condition with a positive increment and a min end condition with a negative increment result in an infinite loop for the exact reason that jeb outlined. When the max value is incremented, it overflows and is interpreted as the min value, so the value never exceeds the end condition.

Dave Benham

dbenham
Expert
Posts: 2288
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Rules for how CMD.EXE parses numbers

#20 Post by dbenham » 20 Sep 2013 12:21

I looked at cmderror's post, and discovered something disturbing on XP.

I couldn't figure out why he was getting overflow with SET /A 0XFFFFFFFF on XP, whereas I was getting a value of -1. Then all of a sudden, I was getting overflow as well. :shock: :? :evil:

I've done some experiments on XP, and determined that:

1) A brand new CMD.EXE session will always treat SET /A 0XFFFFFFFF as -1 to start.

2) Once the "arithmetic processor" within CMD.EXE (whatever that is) detects an overflow condition under any context, then from then on, SET /A 0XFFFFFFFF will be treated as an overflow error. This condition can be triggered by overflow in SET /A, IF, FOR /L, FOR "SKIP=", FOR "TOKENS=", or variable expansion with substring operation.


Dave Benham

penpen
Expert
Posts: 1725
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Rules for how CMD.EXE parses numbers

#21 Post by penpen » 20 Sep 2013 12:47

dbenham wrote:I disagree with penpen and agree with jeb. Penpen is assuming FOR /L uses the same parsing rules as SET /A. You must remember that SET /A has its own rules that differ from all the other contexts.
No, i don't i also use the normal int32 behavior and assume that it may be bound to maximum.


dbenham wrote:I believe FOR /L is using the same parsing rules that I outlined for the IF command:
dbenham wrote:All three numeric notations employ a similar strategy: First ignore any leading negative sign and convert the number into an unsigned binary representation. Then apply any leading negative sign by taking the 2's compliment.

The big difference (from SET /A) is that overflow conditions no longer result in an error. Instead the maximum magnitude value is used. A positive overflow becomes 2147483647, and a negative overflow becomes -2147483648.

Here is my proof:

Code: Select all

C:\test>for /L %N in (999999999999999 -1 2147483645) do @echo %N
2147483647
2147483646
2147483645

C:\test>for /L %N in (-999999999999999 1 -2147483645) do @echo %N
-2147483648
-2147483647
-2147483646
-2147483645

C:\test>for /L %N in (0xFFFFFFFFFFFFF -1 0x7FFFFFFD) do @echo %N
2147483647
2147483646
2147483645

C:\test>for /L %N in (-0xFFFFFFFFFFFFF 1 -0x7FFFFFFD) do @echo %N
-2147483648
-2147483647
-2147483646
-2147483645

C:\test>for /L %N in (07777777777777777777777777 -1 017777777775) do @echo %N
2147483647
2147483646
2147483645

C:\test>for /L %N in (-07777777777777777777777777 1 -017777777775) do @echo %N
-2147483648
-2147483647
-2147483646
-2147483645

I used a similar proof above:
penpen wrote:

Code: Select all

Z:\>for /l %M in (2147483648  1 2147483648) do ( echo %M & pause )


And in Addition i did used the special value 0x8000000 because of the reason, that it's two complements value is again 0x8000000, so it doesn't have any effect.
And if it is computed as you assume, then this should be the result of 0x80000000, -0x80000000:
First ignore any leading negative sign and convert the number into an unsigned binary representation: 0x80000000, 0x80000000.
Then apply any leading negative sign by taking the 2's compliment: 0x80000000, 0x80000000.

In addition even if it tranformed to an decimal interchange Format the result should be the same: as -0x80000000 ==
-(-2147483648)=2147483648.
And even if you aplly the bound to the Maximum value will not change this number.

So if you were right, then for loops i've given above should in all these case do the same:
penpen wrote:for /l %M in (2147483646 1 0x80000000) do ( echo %M & pause )
for /l %M in (2147483646 1 -0x80000000) do ( echo %M & pause )

But they have a different behavior, so what you have assumed above cannot be right.
And i've given above do not depend to any implementation:
(**) serves: counter <=(*) 2147483647, counter in { -2147483648, 2147483647 }
(*) serves:counter (<= 2147483647) <= 2147483648, counter in { -2147483648, 2147483647 } (convert to upper bound possible)
(***) serves: -2147483648 = 0x80000000 != -0x80000000 AND ((s/u)int32 arithmetic) 0x80000000 == -0x80000000 ==> (s/u)int32 arithmetic is not used here.

That -0x80000000 should be equal to 0x80000000 == -2147483648 can be seen here:

Code: Select all

Z:\>for /L %a in (-0x80000000, 1, 2147483647) do (echo %a & pause)

Z:\>(echo -2147483648   & pause)
-2147483648
Drücken Sie eine beliebige Taste . . .

Edit: I've just seen that 0x80000000 is clamped to 2147483647 on Win 7, so this behavior can be explained with clamping, too.
Edit2: Added "on Win 7" to the edit, as the XP 64 here (no patches for whatever reasons, not mine) behaves different.
Edit 3: With "this behavior" in Edit 1 i meant -0x80000000 != 0x80000000, but to be able to differ you need additional Information (at least one additional bit).

penpen
Last edited by penpen on 20 Sep 2013 13:19, edited 3 times in total.

penpen
Expert
Posts: 1725
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Rules for how CMD.EXE parses numbers

#22 Post by penpen » 20 Sep 2013 12:55

jeb wrote:All values greater/equal 0x80000000 are set to 2147483647.
So my pseudo code still stands.
I didn't doubt your pseudocode.
Your pseudocode just doesn't respect that an internal representation might have a different (to sint32) integer representation representation.
The Interpreter just must be able to differ between 0x80000000 in unsigned int 32 and signed int 32 which is not possible with sint32 as the only representation.

This is what i've wanted to say in my above posts (maybe it was not clear enough).

penpen

dbenham
Expert
Posts: 2288
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Rules for how CMD.EXE parses numbers

#23 Post by dbenham » 20 Sep 2013 15:30

penpen wrote:And in Addition i did used the special value 0x8000000 because of the reason, that it's two complements value is again 0x8000000, so it doesn't have any effect.
And if it is computed as you assume, then this should be the result of 0x80000000, -0x80000000:
First ignore any leading negative sign and convert the number into an unsigned binary representation: 0x80000000, 0x80000000.
Then apply any leading negative sign by taking the 2's compliment: 0x80000000, 0x80000000.

In addition even if it tranformed to an decimal interchange Format the result should be the same: as -0x80000000 ==
-(-2147483648)=2147483648.
And even if you aplly the bound to the Maximum value will not change this number.

So if you were right, then for loops i've given above should in all these case do the same:
penpen wrote:for /l %M in (2147483646 1 0x80000000) do ( echo %M & pause )
for /l %M in (2147483646 1 -0x80000000) do ( echo %M & pause )

But they have a different behavior, so what you have assumed above cannot be right.
And i've given above do not depend to any implementation:
(**) serves: counter <=(*) 2147483647, counter in { -2147483648, 2147483647 }
(*) serves:counter (<= 2147483647) <= 2147483648, counter in { -2147483648, 2147483647 } (convert to upper bound possible)
(***) serves: -2147483648 = 0x80000000 != -0x80000000 AND ((s/u)int32 arithmetic) 0x80000000 == -0x80000000 ==> (s/u)int32 arithmetic is not used here.

That -0x80000000 should be equal to 0x80000000 == -2147483648 can be seen here:

Code: Select all

Z:\>for /L %a in (-0x80000000, 1, 2147483647) do (echo %a & pause)

Z:\>(echo -2147483648   & pause)
-2147483648
Drücken Sie eine beliebige Taste . . .

Edit: I've just seen that 0x80000000 is clamped to 2147483647 on Win 7, so this behavior can be explained with clamping, too.
Edit2: Added "on Win 7" to the edit, as the XP 64 here (no patches for whatever reasons, not mine) behaves different.
Edit 3: With "this behavior" in Edit 1 i meant -0x80000000 != 0x80000000, but to be able to differ you need additional Information (at least one additional bit).

No, you misunderstood my rules. But I can see why as I was not clear about what I meant by "overflow condition".

Here is my original statement:
dbenham wrote:All three numeric notations employ a similar strategy: First ignore any leading negative sign and convert the number into an unsigned binary representation. Then apply any leading negative sign by taking the 2's compliment.

The big difference (from SET /A) is that overflow conditions no longer result in an error. Instead the maximum magnitude value is used. A positive overflow becomes 2147483647, and a negative overflow becomes -2147483648.

What was left unsaid is that overflow is detected after the initial unsigned parsing if the 32nd bit (the sign bit of a signed integer) is set. I described this in my original post when talking about SET /A.

However, I think it is more precise to say overflow is detected if the original unsigned parsing requires more than 31 bits.

If no overflow is detected, and the minus sign is missing, then the original parsed value is used.

If no overflow is detected, and the minus sign is present, then the negative value is computed as the two's compliment of the original unsigned value.

If overflow is detected, and the minus sign is missing, then the maximum 32 bit signed integer value is used: 2147483647.

If overflow is detected, and the minus sign is present, then the minimum 32 bit signed integer value is used: -2147483648.

Some additional rules:

The FOR /L parser reads a token as a number up until it detects a character that is invalid as a number. For example: 45HELLO is treated as 45. -123GOODBYE is treated as -123.

If the entire token is invalid, then it is treated as 0. For example: HELLO45 is treated as 0. --123 is treated as 0 (only one minus sign allowed).

The above model account for all of the behavior.

I think your model may also work, but I find it simpler to restrict the model to 32 bits.

Without looking at the cmd.exe code, we can never be sure exactly what is happening. But we can document the behavior :) A working model just makes it easier to document the behavior.


Dave Benham

dbenham
Expert
Posts: 2288
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Rules for how CMD.EXE parses numbers

#24 Post by dbenham » 20 Sep 2013 19:21

I've updated the initial post to include "recently" discovered information, starting with cmderror's post.


Dave Benham

dbenham
Expert
Posts: 2288
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Rules for how CMD.EXE parses numbers

#25 Post by dbenham » 22 Sep 2013 10:05

In a private message, penpen reports that a friend gets different SET /A behavior on XP 64:

Code: Select all

C:\Temp>set /A TEST=0x80000000
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.

Or in English:

Code: Select all

C:\Temp>set /A TEST=0x80000000
Invalid number.  Numbers are limited to 32-bits of precision.

I only just learned that even though I am running Win 7 64 bit, my virtual XP mode is 32 bit. (The Windows virtual machine only supports 32 bit OS)

So I cannot run the tests on XP 64.

On XP 32 I get:

Code: Select all

Z:\>set /a 0x80000001
-2147483647

I would love to get more details about the SET /A behavior on XP 64.

Questions:

1) Does the error still happen with a brand new cmd.exe session? Or does it only occur after at least one legitimate overflow has been issued?

2) Does it happen only with 0x80000000? or with any value that has the sign bit set? Things to try:

set /a 0x80000001 --> on XP 32 this yields -2147483647

set /a 2147483648 --> on XP 32 this yields -2147483648


Dave Benham

penpen
Expert
Posts: 1725
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Rules for how CMD.EXE parses numbers

#26 Post by penpen » 23 Sep 2013 15:52

dbenham wrote:1) Does the error still happen with a brand new cmd.exe session? Or does it only occur after at least one legitimate overflow has been issued?
It happens every time, without any conditions.

dbenham wrote:2) Does it happen only with 0x80000000? or with any value that has the sign bit set? Things to try:

set /a 0x80000001 --> on XP 32 this yields -2147483647

set /a 2147483648 --> on XP 32 this yields -2147483648

Code: Select all

:: put it here togather, but all set /A instructions are executed in their own shell instance as the first command
Z:\>set /A 0x80000001
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.

Z:\>set /A 2147483648
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.

:: with errorlevel information
Z:\>set /A "test=0x80000001"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.

Z:\>echo %test%, %errorlevel%
%test%, 9168

Z:\>set /A "test=2147483648"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.

Z:\>echo %test%, %errorlevel%
%test%, 9168

penpen

npocmaka_
Posts: 481
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Rules for how CMD.EXE parses numbers

#27 Post by npocmaka_ » 25 Oct 2013 07:11

One more forgotten case .. IF [NOT] ERRORLEVEL N .And works surprisingly correct .
It should detect if the current errorlevel is bigger or equals to the given number.Does not accept non-numerical strings.

As exit /b it clears the leading zeros.

Code: Select all

C:\Windows\system32>cmd /c exit /b 11

C:\Windows\system32>if errorlevel 0010 echo yes
yes


but does not overflow as exit /b:




Code: Select all

C:\Windows\system32>cmd /c exit /b 2147483648

C:\Windows\system32>echo %errorlevel%
-2147483648

C:\Windows\system32>if errorlevel 2147483648 echo yes
cm
C:\Windows\system32>

C:\Windows\system32>if errorlevel -2147483649 echo yes
yes

C:\Windows\system32>cmd /c exit /b -2147483648

C:\Windows\system32>if errorlevel 2147483650 echo yes

C:\Windows\system32>if errorlevel 2147483658 echo yes

C:\Windows\system32>if errorlevel 0 echo yes

C:\Windows\system32>if errorlevel -2147483658 echo yes
yes

C:\Windows\system32>if errorlevel -2147483758 echo yes
yes

C:\Windows\system32>if errorlevel -9997483758 echo yes
yes

C:\Windows\system32>


(not the fastest way to?) check if a string is a number:

Code: Select all

(if errorlevel %number% break )>nul 2>&1&& echo it is a number

MtheK
Posts: 5
Joined: 22 Jan 2014 07:32

Re: Rules for how CMD.EXE parses numbers

#28 Post by MtheK » 22 Jan 2014 08:02

In Win7, I have a .BAT that tries to process a negative ERRORLEVEL, but does so rather poorly, and I was hoping that a better way could be found.

I have a program that can do an INT3 which forces an rc of -2147483645; 80000003h. My .BAT can only seem to handle this correctly by doing this after the .EXE call:

Code: Select all

set DSNTODAYrc=%errorlevel%

if ERRORLEVEL  0                GOTO ERRORCONT03
if ERRORLEVEL  -4294967295      GOTO ERRORNEG
:ERRORCONT03

if ERRORLEVEL  1073807365       GOTO ERRORMAX
if ERRORLEVEL  1073807364       GOTO ERRORWTK
if %DSNTODAYrc% GEQ 10010       GOTO ERROR10010

...

:ERRORNEG
if %DSNTODAYrc% ==  -1          GOTO ERRORM1
if %DSNTODAYrc% GEQ -1073741501 GOTO ERRORF0A
if %DSNTODAYrc% ==  -1073741502 GOTO ERRORF0
if %DSNTODAYrc% GEQ -1073741509 GOTO ERRORF1A
if %DSNTODAYrc% ==  -1073741510 GOTO ERRORF1
if %DSNTODAYrc% GEQ -1073741818 GOTO ERRORF2A
if %DSNTODAYrc% ==  -1073741819 GOTO ERRORF2
if %DSNTODAYrc% GEQ -1073807363 GOTO ERRORF3A
if %DSNTODAYrc% ==  -1073807364 GOTO ERRORF3
if %DSNTODAYrc% GEQ -2147483644 GOTO ERRORF4A
if %DSNTODAYrc% ==  -2147483645 GOTO ERRORF4
if %DSNTODAYrc% GEQ -2147750686 GOTO ERRORF5A
if %DSNTODAYrc% ==  -2147750687 GOTO ERRORF5
if %DSNTODAYrc% GEQ -4294967294 GOTO ERRORF6A
if %DSNTODAYrc% ==  -4294967295 GOTO ERRORF6


In this case, the ERRORF4 branch is correctly taken which does this:
ECHO %~n0 %date% %time% error -2147483645; 80000003h ANY(!!!) INT3 CAUSES THIS???!!!
DSNTODAY Tue 01/21/2014 21:24:58.98 error -2147483645; 80000003h ANY(!!!) INT3 CAUSES THIS???!!!

However, if I remove statements 2,3,4 (after SET), the ERROR10010 branch is wrongly taken which does this:
echo %~n0 %date% %time% error rc GE 10010 / %DSNTODAYrc%
DSNTODAY Tue 01/21/2014 21:23:59.54 error rc GE 10010 / -2147483645

I can't figure out why the sign isn't being considered. I tried adding /A in
statement 1 but it fails the same way.

I made a simple .BAT to test it, and it fails the same way:

Code: Select all

rem   both NEG fails w/NO1, POS works ???!!!

set /A DSNTODAYrc=-2147483645
rem set /A DSNTODAYrc=0x80000003
rem set /A DSNTODAYrc=1073807364

rem @ECHO OFF

IF %DSNTODAYrc% GEQ 10010        GOTO NO1
IF %DSNTODAYrc% GEQ -2147483644  GOTO NO2
IF %DSNTODAYrc% ==  -2147483645  GOTO YES

rem IF %DSNTODAYrc% GEQ 1073807365  GOTO NO2
rem IF %DSNTODAYrc% ==  1073807364  GOTO YES

GOTO NO3

:YES
echo YES / %DSNTODAYrc%
GOTO END
:NO1
echo NO1 / %DSNTODAYrc%
GOTO END
:NO2
echo NO2 / %DSNTODAYrc%
GOTO END
:NO3
echo NO3 / %DSNTODAYrc%

:END


C:\Windows\System32>set /A DSNTODAYrc=0x80000003
C:\Windows\System32>IF -2147483645 GEQ 10010 GOTO NO1
C:\Windows\System32>echo NO1 / -2147483645

C:\Windows\System32>set /A DSNTODAYrc=-2147483645
C:\Windows\System32>IF -2147483645 GEQ 10010 GOTO NO1
C:\Windows\System32>echo NO1 / -2147483645

Using /A or not makes no difference w/the decimal #:

C:\Windows\System32>set DSNTODAYrc=-2147483645
C:\Windows\System32>IF -2147483645 GEQ 10010 GOTO NO1
C:\Windows\System32>echo NO1 / -2147483645


What am I doing wrong? Thankx...

MtheK
Posts: 5
Joined: 22 Jan 2014 07:32

Re: Rules for how CMD.EXE parses numbers

#29 Post by MtheK » 30 Jan 2014 07:12

My simple .BAT ain't so simple now, but I narrowed it down:
specifically, using a VAR with a number OTHER THAN ZERO only works,
apparently, for ERRORLEVEL:
[code]
C:\Windows\System32>h:\d\tools\myprogs\dostips1.bat 4
req=4, ERRORLEVEL via DSNTODAY and EL NOT(!) CHECKED
PATHSET DSNTODAY,0,E,"",h:\D\TOOLS\MYPROGS,Wed.01222014,20081716
DSNTODAY Wed 01/22/2014 20:08:18.17 error -2147483645; 80000003h ANY(!!!) INT3 CAUSES THIS???!!!
Press any key to continue . . .
h:\d\TOOLS\MYPROGS>set DSNTODAYrc= (discard called .BATs' SET)
h:\d\TOOLS\MYPROGS>set /A DSNTODAYrc=-2147483645 (from %errorlevel%)
h:\d\TOOLS\MYPROGS>IF -2147483645 GEQ 10010 GOTO NO1 (targ; false, but TAKES BRANCH!!!)
resp=NO1, targ=-2147483645, errlev=-2147483645 (targ and errlev same???)
PATHSET DSNTODAY,0,D,,,Wed.01222014,20081716
[code]
%%%%% FINALLY "FIXED" IT !!!!!!!!!!!!!!!!!!!!!!!!!
[code]
h:\d\TOOLS\MYPROGS>h:\d\tools\myprogs\dostips1.bat 4
req=4, ERRORLEVEL via DSNTODAY and EL NOT(!) CHECKED
PATHSET DSNTODAY,1,E,"",h:\D\TOOLS\MYPROGS,Thu.01232014,14190466
DSNTODAY Thu 01/23/2014 14:19:07.39 error -2147483645; 80000003h ANY(!!!) INT3 CAUSES THIS???!!!
Press any key to continue . . .
h:\d\TOOLS\MYPROGS>set DSNTODAYrc=
h:\d\TOOLS\MYPROGS>set /A DSNTODAYrc=-2147483645

h:\d\TOOLS\MYPROGS>IF -2147483645 GEQ 0 GOTO ERRORCONT03B (FINALLY!!! NO BRANCH!)
h:\d\TOOLS\MYPROGS>GOTO ERRORNEG03 (TA-DA!!!)

h:\d\TOOLS\MYPROGS>IF -2147483645 GEQ -2147483644 GOTO NO2
h:\d\TOOLS\MYPROGS>IF -2147483645 EQU -2147483645 GOTO YES
resp=YES, targ=-2147483645, errlev=-2147483645
PATHSET DSNTODAY,1,D,,,Thu.01232014,14190466
[code]

Comments?

MtheK
Posts: 5
Joined: 22 Jan 2014 07:32

Re: Rules for how CMD.EXE parses numbers

#30 Post by MtheK » 10 Feb 2014 06:40

For some weird reason, non-ADMIN, the IF fails to compare correctly if not compared with a ZERO and thus the GOTO is wrongly taken (ie: it says a NEG# is GE a POS#):

Code: Select all

C:\Windows\System32>h:\d\tools\myprogs\dostips1.bat 4
req=4, ERRORLEVEL via DSNTODAY and EL NOT(!) CHECKED
PATHSET DSNTODAY,0,E,"",h:\D\TOOLS\MYPROGS,Wed.01222014,20081716
 DSNTODAY Wed 01/22/2014 20:08:18.17 error -2147483645; 80000003h ANY(!!!) INT3 CAUSES THIS???!!!
Press any key to continue . . .
h:\d\TOOLS\MYPROGS>set DSNTODAYrc=                              (discard called .BATs' SET)
h:\d\TOOLS\MYPROGS>set /A DSNTODAYrc=-2147483645                (from %errorlevel%)
h:\d\TOOLS\MYPROGS>IF -2147483645 GEQ 10010 GOTO NO1            (targ; false, but TAKES BRANCH!!!)
resp=NO1, targ=-2147483645, errlev=-2147483645                  (targ and errlev same???)


%%%%% FINALLY "FIXED" IT!!!!!!!!

Code: Select all

h:\d\TOOLS\MYPROGS>h:\d\tools\myprogs\dostips1.bat 4
req=4, ERRORLEVEL via DSNTODAY and EL NOT(!) CHECKED
PATHSET DSNTODAY,1,E,"",h:\D\TOOLS\MYPROGS,Thu.01232014,14190466
 DSNTODAY Thu 01/23/2014 14:19:07.39 error -2147483645; 80000003h ANY(!!!) INT3 CAUSES THIS???!!!
Press any key to continue . . .
h:\d\TOOLS\MYPROGS>set DSNTODAYrc=
h:\d\TOOLS\MYPROGS>set /A DSNTODAYrc=-2147483645

h:\d\TOOLS\MYPROGS>IF -2147483645 GEQ 0 GOTO ERRORCONT03B       (FINALLY!!! NO BRANCH!)
h:\d\TOOLS\MYPROGS>GOTO ERRORNEG03                              (TA-DA!!!)

h:\d\TOOLS\MYPROGS>IF -2147483645 GEQ -2147483644 GOTO NO2
h:\d\TOOLS\MYPROGS>IF -2147483645 EQU -2147483645 GOTO YES
resp=YES, targ=-2147483645, errlev=-2147483645

Post Reply