Solved

C++ ((16-bit minus 32-bit) < 0) always false?

Posted on 2014-04-08
5
288 Views
Last Modified: 2014-04-08
#include "stdafx.h"
typedef unsigned short u16;
typedef unsigned long  u32;

int _tmain(int argc, _TCHAR* argv[])
{
  u16 x = 0;
  u32 y = 6;
  int z = 0;

  if ( (x - (y*7)) < 0)
  {
    z = 1;
  }

  return 0;
}

Open in new window

The problem is line 11, the if statement. Viewing the disassembly, the assembly code generated ends with a jmp statement, always skipping over the z = 1;, implying the condition is always FALSE no matter what values are used for x and y.

Why? Has something to do with mixing 16-bit and 32-bit integers.
disassembly.png
0
Comment
Question by:deleyd
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
5 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 39986927
The problem is that you are using unsigned variables - these can never by smaller than null by definition, that's why. Just remove the 'unsigned' declaration and everything works as expected.
0
 
LVL 86

Expert Comment

by:jkr
ID: 39986937
BTW, to illustrate that:

#include <tchar.h>
#include <stdio.h>
typedef unsigned short u16;
typedef unsigned long  u32;
typedef short i16;
typedef long  i32;


int _tmain(int argc, _TCHAR* argv[])
{
  u32 x = 0;
  u32 y = 6;
  int z = 0;

  i32 x1 = 0;
  i32 y1 = 6;

  if ( (x - (y*7)) < 0)
  {
    printf("true for unsigned types\n");
  }
  else printf("false for unsigned types\n");

  if ( (x1 - (y1*7)) < 0)
  {
    printf("true for signed types\n");
  }
  else printf("false for signed types\n");

  return 0;
}
                                  

Open in new window


Output:

false for unsigned types
true for signed types
0
 
LVL 86

Expert Comment

by:jkr
ID: 39986947
BTW², extended demonstration with the calculated values, so you'll see what actually happens behind the scenes:

#include <tchar.h>
#include <stdio.h>
typedef unsigned short u16;
typedef unsigned long  u32;
typedef short i16;
typedef long  i32;


int _tmain(int argc, _TCHAR* argv[])
{
  u32 x = 0;
  u32 y = 6;
  int z = 0;
  u32 result;

  i32 x1 = 0;
  i32 y1 = 6;
  i32 result1;

  if ((result =  (x - (y*7))) < 0)
  {
    printf("true for unsigned types\n");
  }
  else printf("false for unsigned types\n");

  printf ("result: %u\n", result);

  if ((result1 = (x1 - (y1*7))) < 0)
  {
    printf("true for signed types\n");
  }
  else printf("false for signed types\n");

  printf ("result1: %d\n", result);

  return 0;
}
                                  

Open in new window


Output:

false for unsigned types
result: 4294967254
true for signed types
result1: -42
0
 

Author Comment

by:deleyd
ID: 39987017
How about if I change the unsigned 16-bit to a signed-16 bit?
#include "stdafx.h"
typedef signed short s16;
typedef unsigned long  u32;

int _tmain(int argc, _TCHAR* argv[])
{
  s16 x = 0;
  u32 y = 6;
  int z = 0;

  if (x - y < 0)
  {
    z = 1;
  }

  if (x < y)
  {
    z = 1;
  }
  return 0;
}

Open in new window

Now I have a signed 16-bit subtracting an unsigned 32-bit, and I get an unconditional jmp statement again.

However, if I switch the statement around to compare (x < y), now I'm comparing a signed 16-bit with an unsigned 32-bit, and it works OK.

What's happening?
disassembly2.png
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 39987054
'unsigned' will always have the 'upper hand' when mixing signed and unsigned types - that's a reason why you shouldn't do it. The key here is called 'integer promotion strategy' and you'll find an in-depth explanation here: http://blog.regehr.org/archives/268 ("Why Not Mix Signed and Unsigned Values in C/C++?"). The author discusses the same issue that you are encountering, and I can't agree more when he states ' If this doesn’t give you at least one brief moment of “WTF?” then you’re doing a lot better than I did the first time I saw something like this happen.'

Or, the gist:

The second feature is C’s method for choosing which version of an operator to use. Although the greater-than operator in C always looks like “>”, behind the scenes there are quite a few different operators: signed integer >, unsigned integer >, signed long >, unsigned long >, etc. If either operand to “>” is unsigned, then an unsigned comparison is used, otherwise the comparison is signed.
0

Featured Post

Enroll in May's Course of the Month

May’s Course of the Month is now available! Experts Exchange’s Premium Members and Team Accounts have access to a complimentary course each month as part of their membership—an extra way to increase training and boost professional development.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

710 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question