1
$ gcc --version  
gcc (Debian 4.9.2-10) 4.9.2

In the following code snippet why is the expression 100 < strlen(str) - 4 getting evaluated as true?

#include <stdio.h>
#include <string.h>

int main(void)
{
    char str[50];

    scanf("%s", str);
    printf("%d\n", strlen(str) - 4);

    if(100 < (strlen(str) - 4))
        printf("NOT POSSIBLE!\n");

    return 0;
}

Terminal:

$ gcc so.c -o so  
$ ./so  
foo
-1
NOT POSSIBLE!  

From experimenting a bit I found out :

  1. the if expression evaluates to true for any positive_int, negative_int pair such that positive_int < negative_num (which is absurd) where negative_int is in the form of strlen function call (see 2.)
  2. if we replace the strlen with a hard coded negative integer then if evaluates to false as expected. Looks like there's something wrong with strlen.
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
rootkea
  • 1,474
  • 2
  • 12
  • 32
  • 1
    Because size_t is unsigned. You probably would write `if (100 + 4 < strlen(str))` to avoid issues with negative numbers, thus obtaining correct results. – pablo1977 Dec 27 '15 at 13:45
  • See [this So post](http://stackoverflow.com/questions/2550774/what-is-size-t-in-c) for more info about `size_t` – Arc676 Dec 27 '15 at 13:46

4 Answers4

4

Since strlen has type size_t, 4 is converted to (unsigned) size_t, then deducted from strlen's return value, and then the result is compared with 100.

6.3.1.8 Usual arithmetic conversions
....
Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.

Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

7.24.6.3 The strlen function
....
size_t strlen(const char *s);

7.19 Common definitions
....
size_t which is the unsigned integer type of the result of the sizeof operator;


P.S. BTW, even in a simpler case, as

if (strlen("") < -1)
    printf("OK\n");
else
    printf("NOK\n");

, the output would be OK.

AlexD
  • 32,156
  • 3
  • 71
  • 65
  • @SouravGhosh Perhaps it depends on the version of the standard. I have `N1570`. – AlexD Dec 27 '15 at 13:53
  • So here `3` is an unsigned integer returned by `strlen` and so `4` will be converted to unsigned too. What about the result i.e. `(unsigned)3 - (unsigned)4`? Does the standard guarantee that the operation of two unsigned numbers will yield unsigned value only? – rootkea Dec 27 '15 at 13:57
  • @owacoder Ok. I think I got it. The result of `(unsigned)3 - (unsigned)4` is equal to `(unsigned)(-1)` which is pretty large than `(unsigned) 100`. Is it correct interpretation? – rootkea Dec 27 '15 at 14:02
  • 1
    @rootkea I updated the post to include " _if both operands have signed integer types or both have unsigned integer types..._". – AlexD Dec 27 '15 at 14:07
4

strlen() will return an unsigned value, so strlen(str) - 4 will be unsigned number which is "very big", and it will be larger than 100.

Try casting the return value to int if you won't deal with very long strings.

#include <stdio.h>
#include <string.h>

int main(void)
{
    char str[50];

    scanf("%49s", str); /* specify size to avoid buffer overrun */
    printf("%d\n", (int)strlen(str) - 4);

    if(100 < ((int)strlen(str) - 4))
        printf("NOT POSSIBLE!\n");

    return 0;
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
2

strlen returns an unsigned integer of type size_t. When subtracting 4 from an unsigned 3, unsigned integers will wrap to the largest representable number, thus always being larger than 100.

owacoder
  • 4,815
  • 20
  • 47
2

Quoting C11, chapter §7.23.6.3, The strlen() function

size_t strlen(const char *s);

the return type of strlen() is size_t, and as per chapter §7.19, (emphasis mine)

size_t

which is the unsigned integer type of the result of the sizeof operator;

and 100 and 4 are int literal, which is of signed type here, referring chapter §6.4.4.1

The type of an integer constant is the first of the corresponding list in which its value can be represented.

You're trying to perform an arithmetic operation (subtraction) involving a signed type with unsigned type, hence the signed type is getting promoted to unsigned type before comparison. Thus, the result is of type unsigned and the final result of the comparison comes as TRUE.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261