overexchange
overexchange

Reputation: 1

Implicit conversion using Comparison operator

In the below code,

#include<stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))

int main(void){
  int array[] = {7,5,4,3,2};
  int index = -1;
  for(;index <= TOTAL_ELEMENTS-2;index++)
    printf("%d\n", array[index+1]);
  return 0;
}

index <= TOTAL_ELEMENTS-2 fail before printing single element.

Is it not the condition -1 <= (5-2), that is being evaluated in for-loop?

Upvotes: 1

Views: 325

Answers (3)

AndersK
AndersK

Reputation: 36092

The division sizeof(array)/sizeof(array[0]) results in an unsigned int so when comparing with index = -1 or subtracting from it will be implicitly cast to unsigned int i.e. 0xffffffff and so the condition fails.

Instead just do a explicit cast in your macro

#define TOTAL_ELEMENTS (int)(sizeof(array) / sizeof(array[0]))

personally i would instead use an argument to your TOTAL_ELEMENTS

#define TOTAL_ELEMENTS(ar) (int)(sizeof(ar))/sizeof(ar[0]))

to make to code a little bit more readable.

Upvotes: 1

In the comparison index <= TOTAL_ELEMENTS-2, the left-hand side index has the type int, and the right-hand side TOTAL_ELEMENTS-2 has the type size_t¹. The two operands of the operator have different types, so they need to be converted to a common type. The common type always has the larger of the two sizes², which is size_t (which may be the same as unsigned int on 32-bit machines, but it usually larger on 64-bit machines). And the common type is unsigned in this case, because the right-hand side is at least as large.

The common type is always chosen so that it can represent the maximum positive value of both types. If this results in an unsigned type then it can't represent negative values.

Here the variable index is an array index, so it should have the type size_t. The type int may be too small to represent all array indices.

size_t is an unsigned type; unsigned values are easier to manipulate, and have predictable behavior on overflow, so generally speaking you should use unsigned types unless you need negative values. (Overflow is still a problem with unsigned types, but at least the behavior is well-defined so the problem is easier to debug.) Here there's no point in having a variable with negative values: use index as the array index, instead of the array index minus one, and then it'll start at 0 instead of 1.

size_t index;
for(index = 0; index <= TOTAL_ELEMENTS-1; index++) {
    printf("%d\n", array[index]);
}

¹ Or unsigned int if size_t is smaller than int, e.g. if it's unsigned short, but it would be very unusual for a C implementation to be like this.
² In technical terms, the larger of the two ranks.

Upvotes: 0

P.P
P.P

Reputation: 121417

sizeof(array) / sizeof(array[0]) yields 5 which is of type size_t. As a result, the type of the expression sizeof(array) / sizeof(array[0])-2 is also size_t, which is an unsigned integer type. The LHS of the comparison also gets promoted to size_t type (see usual arithmeic conversions) and -1 is equal to SIZE_MAX (the maximum value that a size_t can hold) after the conversion.

Hence, the comparsion index <= TOTAL_ELEMENTS-2, which is equivalent to SIZE_MAX <= 3, is false.

Upvotes: 2

Related Questions