16

A friend gave me a riddle:

#include<stdio.h>

#define TOTAL_ELEMENTS ((sizeof(array) / sizeof(array[0])))
  int array[] = {23,34,12,17,204,99,16};

  int main()
  {
      int d;
      for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
          printf("%d\n",array[d+1]);
      getchar();
      return 0;
  }

The above code is supposed to print all the array elements, what is the problem in the code (the output is nothing)? I think the loop doesn't iterate even once?

I found out that the following code does work:

#include<stdio.h>



#define TOTAL_ELEMENTS ((sizeof(array) / sizeof(array[0])))
  int array[] = {23,34,12,17,204,99,16};

  int main()
  {
      int d;
      int x = (TOTAL_ELEMENTS-2);
      for(d=-1;d <= x;d++)
          printf("%d\n",array[d+1]);
      getchar();
      return 0;
  }

I have a theory that it's something to do with the macro, but I can't put my finger on the problem.

rolfl
  • 17,539
  • 7
  • 42
  • 76
Gilad Naaman
  • 6,390
  • 15
  • 52
  • 82
  • 3
    When you say something "doesn't work", you must say how what it *does* is different from what you *expect*. – Gabe Apr 10 '11 at 12:35
  • possible duplicate of [Confused about C macro expansion and integer arithmetic](http://stackoverflow.com/questions/950051/confused-about-c-macro-expansion-and-integer-arithmetic) – assylias Jul 01 '12 at 17:56

4 Answers4

35

The problem is that (TOTAL_ELEMENTS-2) is an unsigned value. When you make the comparison d <= (TOTAL_ELEMENTS-2), both values are converted to unsigned values, and the result is false.

In your second example, x is signed so there is no problem.

interjay
  • 107,303
  • 21
  • 270
  • 254
  • 5
    And thats why almost everyone write this kind if loop in a way that reduce signed/unsigned errors: for(d = 0; d < TOTAL_ELEMENTS; d++) printf("%d\n",array[d]); – Zuljin Apr 10 '11 at 12:48
8

The sizeof operator yields a result of type size_t. In the first version, you are comparing an int (signed) against a size_t (unsigned).

In the second version, you convert the size_t expression to an int by assigning it, and hence both operands of the comparison are of the same type.

Blagovest Buyukliev
  • 42,498
  • 14
  • 94
  • 130
3

One another way of seeing this problem as follow

#include<stdio.h>

int main() {

int i = -5;
unsigned int j = 6;

if(i < j)
  printf("-5 is less than 6");
else
  printf("-5 is greater than 6");

return 0;
}

Output is:

-5 is greater than 6

Reason: Comparing unsigned integer with signed integer will always return false.

In the questioner case the sizeof returns unsigned data type but it is compared with signed data type (- is a bug)

SridharKritha
  • 8,481
  • 2
  • 52
  • 43
  • “Comparing unsigned integer with signed integer will always return false.” This is the wrong explanation. `12 > 7U` evaluates to the expected result, `1`. The question has been adequately covered by interjay's answer and there is no point in adding such a fuzzy and incoherent explanation to it. – Pascal Cuoq Jul 27 '13 at 23:40
  • Yes, no doubt I agree interjay's answer fully addresses the questioner problem. In my last reply I'm just tried to show the root cause of same kind of problem with another very simple code. Also my explanation - Comparing unsigned integer with signed integer will always return false is the reason for this specific case. Thanks – SridharKritha Jul 28 '13 at 19:19
0

I run the following program without using any macro and output was nothing

#include<stdio.h>
int main()
{
  int d;
for(d=-1;d<=sizeof(int);d++)
{  
 printf("sizeof operator\n");
}
return 0;
}

So it means that problem is not in MACRO but the type of value sizeof returns. sizeof returns size of data type as size_t which is unsigned but -1 implicitly gets converted to unsigned which is 0xffffffff and is obviously greater than sizeof(int). Also look at Noncompliant Code Example (Comparison)

Deepak Uniyal
  • 89
  • 3
  • 16