3

I tried to compare with strlen(string) with -1 but different methods gave different results:

char string[] = {"1234"};
int len = strlen(string);
int bool;
bool = -1 < strlen(string);
printf("%d",bool); //bool=0
bool = -1 < len;
printf("%d",bool); //bool=1

Assigning values to len and then comparing them gives the correct result, but I don't understand why directly comparing with strlen doesn't work.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
chaganhu
  • 33
  • 3
  • 2
    The value returned by strlen() is `size_t` type https://cplusplus.com/reference/cstring/strlen/?kw=strlen – Filippo Nov 08 '22 at 07:19
  • Naming a variable `bool` is confusing, and a bad idea. `bool` is a type alias of `_Bool` defined in stdbool.h. So most readers would expect that to be a type name, not a variable name. – Clifford Nov 08 '22 at 07:48
  • See [Implicit type promotion rules](https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules). After studying that, note that `strlen` returns `size_t` which has very high conversion rank, likely same as `unsigned long` or `unsigned long long`. – Lundin Nov 08 '22 at 09:28

3 Answers3

3

The function strlen has the unsigned return type size_t

size_t strlen(const char *s);

Usually the type size_t is an alias for the type unsigned long.

In any case the rank of the unsigned type size_t is not less than the rank of the signed type int. So due to the usual arithmetic conversion an operand of the signed type int is converted to the type size_t and if the operand of the type int has a negative value than due to propagating the sign bit it becomes a big unsigned value.

So in this expression

-1 < strlen(string)

of the type size_t (the common type of the expression) the left operand after conversion to the type size_t becomes greater than the right operand.

Consider the following demonstration program.

#include <stdio.h>

int main( void )
{
    printf( "-1 = %d\n", -1 );
    printf( "( size_t )-1 = %zu\n", ( size_t )-1 );
    return 0;
}

Its output might look like

-1 = -1
( size_t )-1 = 4294967295
unwind
  • 391,730
  • 64
  • 469
  • 606
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks! I now know that the return value of strlen() is unsigned. – chaganhu Nov 08 '22 at 07:39
  • 1
    Pedantic: "the rank of the unsigned type size_t is not less than the rank of the signed type int" --> this is _overwhelmingly common_, yet not required by C. `size_t` could be like `unsigned short` for example. – chux - Reinstate Monica Nov 08 '22 at 16:32
1

Comparison occurs between different type pairs:

//int  size_t
  -1 < strlen(string);
//int  int
  -1 < len;

-1 < len behaves as expected as both types are the same.

With int/size_t one of the types is converted. First any type narrower than int/unsigned is promoted to int/unsigned without changing value.

Then the lower ranked type is converted to the other. size_t, some unsigned type, is very often of higher rank than int and so -1 is converted to an size_t and value by adding SIZE_MAX + 1 resulting in SIZE_MAX < strlen(string), which is false.

Should a rare implementation have size_t of a lower rank than int, the value of strlen(string) would change to type int with the same value and -1 < strlen(string) would be true.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

Sign problem I guess, comparing to strlen must cast -1 to unsigned, so all bits set to 1, so whatever value is compared with, expression evaluates to 0.

While comparing with a typed variable, problem can't occur since compiler doesn't have to guess which operand has to be casted to other type.

What happens if you compile with -Wall -Wextra -Werror? Error because of comparaison between invalid types?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
AR7CORE
  • 268
  • 1
  • 8
  • 1
    There is no need to "guess". Better to post an answer when you "know", otherwise this is a _comment_ not an answer. – Clifford Nov 08 '22 at 07:45
  • 1
    Well, my guess was the only candidate, I don't see any other, I just have the honesty to admit I might be wrong, for some very obscure particularities I could ignore. – AR7CORE Nov 08 '22 at 07:54
  • It is not that your answer is "wrong" as such - you have clearly hit in the right solution, but are not clear why it works. The question is about why the code does not work, not about solving the type mismatch error.. Vlad posted two minutes after you. Apart from that you posted a few minutes after the question. It may take 24 hours for all timezones to wake up and read the question, and a good answer takes time to type in any event. It is not a race. – Clifford Nov 08 '22 at 08:05
  • Solving the mismatch error gives the author a track to understand what's going on, and lets him dig a bit further if he wants to. I'm not in a race, but I wrote answer on my cell phone, and auto-correction makes it hard to write code, so glad Vlad did. As long as author got answer he expected I'm fine, whether it's coming from me or not. But thanks for pointing how I could make my answer better. Comments aren't for debate, so I won't reply any further since thread is now closed, have a nice day, fellow contributor. – AR7CORE Nov 08 '22 at 08:14
  • 1
    "While comparing with a typed variable, problem can't occur" This is not correct. All that matters is whether `-1` of type `int` is compared with another operand of type `int` or with type `size_t`. "The usual arithmetic conversions" are then applied, in the `size_t` case converting `-1` to an unsigned type. – Lundin Nov 08 '22 at 09:31
  • In general, the compiler doesn't guess and neither should you. It knows perfectly well which type `strlen` returns. As for implicit conversions, check out [Implicit type promotion rules](https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules). Also, there is no such thing as "implicit casts", there are implicit or explicit conversions. A cast is always an explicit conversion, carried out by the programmer by using the `(type)` cast operator. – Lundin Nov 08 '22 at 09:34