If statement executes even when condition is false - c

if( (*ptr != ',') || strlen(ptr+1) < sizeof(struct A) * num1)
{
printf("\n Condition satisfied.");
}
This is the code in question. I have a string of the format str = "-1,ABCDEFGH", and a struct A of size 15 bytes.
I'm performing this operation beforehand:
number = strtoul(str, &ptr, 10);
After this operation, ptr points to the ',' and number = -1
Looking at the IF condition, the first statement evaluates to be false (because *ptr = ',') and the second statement executes to be TRUE even though it should be false ( strlen(ptr+1) is positive, and (sizeof(struct A) * number) is negative, simply because num1 is a negative value ).
Why is this statement evaluating to be true and entering the IF block? I'm getting the output 'Condition satisfied', whereas I shouldn't be. Thanks in advance.

(sizeof(struct A) * number) is negative, simply because num1 is a negative value
Not quite. sizeof(struct A) has type size_t (unsigned type).
Assuming that
num is of type int,
precision of signed type, corresponding to size_t is the same as or bigger than precision of int,
sizeof(struct A) * num is an unsigned value (and hence non negative), even if num is negative.
See Arithmetic operators:
Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.
Please note, as #user3386109 commented, that strlen uses an unsigned type too. So there could be the same problem with < as with *.

sizeof(struct A) is undefined and also it is multiplied by a number so it provides a

Related

Not getting expected output for ternary operator

Consider the following code in C :
void main() {
char *x = "abc";
char *y = "defgh";
unsigned int c=0;
int len = ((strlen(x) - strlen(y)) > c) ? strlen(x) : strlen(y);
printf("%d\n", len);
}
I'm getting output as 3, but the condition in ternary operator ((strlen(x) - strlen(y)) > c) is false, because this will be 3-5 > 0 which is false. Hence, the output should be 5. I couldn't understand what went wrong.
The strlen function has a return type of size_t which is an unsigned integer type. This means that strlen(x) - strlen(y) also has this type. So instead of resulting in a value of -2 you get a result which is a very large positive value. This value is greater than 0, so the condition is true.
If you cast the results of these functions to int, you'll get the expected result.
int len = (((int)strlen(x) - (int)strlen(y)) > c) ? strlen(x) : strlen(y);
The result of strlen is size_t, which is an unsigned type. Thus the expression:
((strlen(x) - strlen(y)) > c
effectively expands to:
(((size_t)3 - (size_t)5) > 0
And ((size_t)3 - (size_t)5) is not a negative number (there are no negative size_t values). It is instead a very large unsigned value (e.g. 0xFFFFFFFFFFFFFFFE for a 64-bit system), which is in fact larger than 0.

Casting to _Bool

Traditionally, Boolean values in C were represented with int or char. The new _Bool type makes intent clearer, but also has another interesting feature: it seems casting floating-point numbers to it, does not truncate toward zero, but compares with exact zero:
#include <stdio.h>
int main(int argc, char **argv) {
double a = 0.1;
int i = (int)a;
printf("%d\n", i);
_Bool b = (_Bool)a;
printf("%d\n", b);
return 0;
}
prints
0
1
So this is a semantic difference. And one I'm happy with; it duplicates the effect of using a floating-point number as a conditional.
Is this something that can be depended on across-the-board? Does the new C standard define the result of casting X to _Bool as identical to X ? 1 : 0 for all X for which that is a valid operation?
In the C Standard (6.3.1.2 Boolean type) there is written
1 When any scalar value is converted to _Bool, the result is 0 if the
value compares equal to 0; otherwise, the result is 1.
That is during conversion to the type _Bool the compiler does not try to represent the value (truncating toward zero or something else) of the operand of an expression with the casting operator as an integer. It only checks whether the value is equal or unequal to zero.
Actually this declaration
_Bool b = (_Bool)a;
is equivalent to
_Bool b = a;
It is entirely consistent, a non-zero value implicitly cast to _Bool is true. Since _Bool is a true Boolean type and not "faked", it can behave correctly. So:
_Bool b = (_Bool)a ;
is equivalent to:
_Bool b = (a == 0) ;
not:
_Bool b = ((int)a == 0) ;
In the end interpreting a float as Boolean is nonsense and ill-advised as is comparing it for equality to zero. If you want the semantic you expect, you must code it explicitly:
_Bool b = (_Bool)((int)a);
Semantically that is equivalent to :
_Bool b = (a < 1.0);
It is clearer and safer to use a Boolean expression than to force a value to Boolean with a cast.

How are these two methods to find what power of 2 a number is, different?

So, let's say I have a number N that's guaranteed to be a power of 2 and is always greater than 0. Now, I wrote two C methods to find what power of 2 N is, based on bitwise operators -
Method A -
int whichPowerOf2(long long num) {
int ret = -1;
while (num) {
num >>= 1;
ret += 1;
}
return ret;
}
Method B -
int whichPowerOf2(long long num) {
int idx = 0;
while (!(num & (1<<idx))) idx += 1;
return idx;
}
Intuitively, the two methods seem one and the same and also return the same values for different (smaller) values of N. However, Method B doesn't work for me when I try to submit my solution to a coding problem.
Can anyone tell me what's going on here? Why is Method A right and Method B wrong?
The problem is with this subexpression:
1<<idx
The constant 1 has type int. If idx becomes larger than the bit width of an int, you invoked undefined behavior. This is specified in section 6.5.7p3 of the C standard regarding bitwise shift operators:
The integer promotions are performed on each of the operands. The type
of the result is that of the promoted left operand. If the value of
the right operand is negative or is greater than or equal to the width
of the promoted left operand, the behavior is undefined.
Change the constant to 1LL to give it type long long, matching the type of num.
while (!(num & (1LL<<idx))) idx += 1;
In your Method B, the following line can cause undefined behaviour:
while (!(num & (1<<idx))) idx += 1;
Why? Well, the expression 1<<idx is evaluated as an int because the constant 1 is an int. Further, as num is a long long (which we'll assume has more bits than an int), then you could end up left-shifting by more than the number of bits in an int.
To fix the issue, use the LL suffix on the constant:
while (!(num & (1LL<<idx))) idx += 1;

warning: comparison of unsigned expression >= 0 is always true

I have the following error when compiling a C file:
t_memmove.c: In function ‘ft_memmove’:
ft_memmove.c:19: warning: comparison of unsigned expression >= 0 is always true
Here's the full code, via cat ft_memmove.c:
#include "libft.h"
#include <string.h>
void *ft_memmove(void *s1, const void *s2, size_t n)
{
char *s1c;
char *s2c;
size_t i;
if (!s1 || !s2 || !n)
{
return s1;
}
i = 0;
s1c = (char *) s1;
s2c = (char *) s2;
if (s1c > s2c)
{
while (n - i >= 0) // this triggers the error
{
s1c[n - i] = s2c[n - i];
++i;
}
}
else
{
while (i < n)
{
s1c[i] = s2c[i];
++i;
}
}
return s1;
}
I do understand that size_t is unsigned and that both integers will be >= 0 because of that. But since I'm subtracting one from the other, I don't get it. Why does this error come up?
If you subtract two unsigned integers in C, the result will be interpreted as unsigned. It doesn't automatically treat it as signed just because you subtracted. One way to fix that is use n >= i instead of n - i >= 0.
consider this loop:
for(unsigned int i=5;i>=0;i--)
{
}
This loop will be infinite because whenever i becomes -1 it'll be interprated as a very large possitive value as sign bit is absent in unsigned int.
This is the reason a warning is generated here
According to section 6.3.1.8 of the draft C99 standard Usual arithmetic conversions, since they are both of the same type, the result will also be size_t. The section states:
[...]Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result[...]
and later on says:
If both operands have the same type, then no further conversion is needed.
mathematically you can just move the i over to the other side of the expression like so:
n >= i
Arithmetic on unsigned results in an unsigned and that's why you are getting this warning. Better to change n - i >= 0 to n >= i.
Operations with unsigned operands are performed in the domain of unsigned type. Unsigned arithmetic follows the rules of modular arithmetic. This means that the result will never be negative, even if you are subtracting something from something. For example 1u - 5u does not produce -4. If produces UINT_MAX - 3, which is a huge positive value congruent to -4 modulo UINT_MAX + 1.

A Macro using sizeof(arrays) is not giving the expected output

#include <stdio.h>
int arr[] = {1, 2,3,4,5};
#define TOT (sizeof(arr)/sizeof(arr[0]))
int main()
{
int d = -1, x = 0;
if(d<= TOT){
x = arr[4];
printf("%d", TOT);
}
printf("%d", TOT);
}
TOT has the value 5 but the if condition is failing..why is that?
Because there are "the usual arithmetic conversions" at work for the if.
The sizeof operator returns an unsigned type ... and d is converted to unsigned making it greater than the number of elements in arr.
Try
#define TOT (int)(sizeof(arr)/sizeof(arr[0]))
or
if(d<= (int)TOT){
That's because sizeof returns an unsigned number, while d is signed. When d implicitly converted to a singed number, and then it is much much larger than TOT.
You should get a warning about comparison of signed-unsigned comparison from the compiler.
Your expression for TOT is an unsigned value because the sizeof() operator always returns unsigned (positive) values.
When you compare the signed variable d with it, d gets automatically converted to a very large unsigned value, and hence becomes larger than TOT.
return type of sizeof is unsigned integer ....that is why if is failing ...because "d" which is treated as signed by the compiler is greater than TOT

Resources