automatic type conversions [duplicate] - c

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
signed to unsigned conversions
A riddle (in C)
I am trying to understand why this program is not working
#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]);
return 0;
}
I came across this program when I was going through automatic type conversions in C.But I don't understand how conversions happen between signed and unsigned data types.Please explain.
Thank you,
Harish

sizeof() is of type unsigned, wile d is signed.
you check if d is smaller then an unsigned integer. Thus, the signed d is converted to unsinged.
But the bits representaion of the signed -1 when read as unsigned is greater then 2^31, and obviously greater then TOTAL_ELEMENTS-2, thus the condition is never met and you do not enter the for loop even once.
Look at this code snap, it might clear up things for you:
#include <stdio.h>
#include <stdlib.h>
int main() {
unsigned int x = 50;
int y = -1;
printf("x < y is actually %u < %u which yields %u\n", y,x,y < x);
return 0;
}
The above code prints:
x < y is actually 4294967295 < 50 which yields 0

Related

Why is integer conversion done this way? [duplicate]

This question already has answers here:
Unsigned values in C
(3 answers)
Closed 9 months ago.
I ran into an interesting scenario with integer conversion:
#include <stdio.h>
int main()
{
unsigned int x = 20;
unsigned int y = 40;
printf("%d\n", x - y);
printf("%d\n", (x - y) / 4);
}
~ % ./a.out
-20
1073741819
I wasn't expecting the 2nd result. Since x and y are both unsigned ints is the result of x - y unsigned (and in this case displayed as signed by printf)?
The things you are printing are indeed unsigned integers and you should print them with %u, but that does not explain the surprising result for the second number. The surprising result comes from an overflow occurring when you calculate x - y, since the result of that subtraction is negative and thus not representable as an unsigned int.
Unsigned overflow/underflow is not undefined behavior, so it's OK to have code like this in production if you know what you are doing.

How to write absolute value in c

I know the solution is ugly and technically incorrect but I don't understand why the code doesn't work.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
printf("absValue = %u\n", u);
return 0;
}
%u specifies an unsigned decimal character but when I input a negative value, it gives
absValue = 4294967293
Alternatively, with the if command, how to convert the negative sign to positive?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main (int argc, char *argv[]) {
int n;
scanf("%d", &n);
if(n < 0) {
printf("absValue = -%d\n", n);
} else {
printf("absValue = %d\n", n);
}
return 0;
}
The shortest solution in your first piece of code is to change the printf statement as follows:
printf("absValue = %u\n", (unsigned)((u<0)?-u:u));
This will print the absolute value of u. The type conversion (unsigned) ensures that the data type is as expected by printf. The statement (u<0)?-u:u uses the conditional operator to select the value -u if the condition (u<0) is true and u if the condition is false (i.e. u>=0).
The problem in your code is that u is a signed integer which means its value is stored using the Two's complement representation in 4 bytes(*) and printf is not intelligent. When you tell printf to display an unsigned integer, then printf will take the 4 bytes holding u and interpret them as an unsigned integer. Since negative numbers in Two's complement are stored as large positive integers, that is the result you see.
(*) The use of Two's complement and the int size of 4 is machine-dependent, but common.
As an alternative, you can also use the standard C function abs() (or one of its related functions):
7.22.6.1 The abs, labs and llabs functions
Synopsis
#include <stdlib.h>
int abs(int j);
long int labs(long int j);
long long int llabs(long long int j);
Description
The abs, labs, and llabs functions compute the absolute value of
an integer j. If the result cannot be represented, the behavior is
undefined.
Returns
The abs, labs, and llabs, functions return the absolute value.
Footnotes
The absolute value of the most negative number cannot be represented
in two's complement.
Note the footnote "The absolute value of the most negative number cannot be represented in two's complement." and "If the result cannot be represented, the behavior is undefined." Strictly speaking, you'd likely need to use long long int and llabs() to avoid undefined behavior in converting INT_MIN to a positive value, assuming a 32-bit int value, and long is often 32-bits, even on 64-bit Windows.
However, since double values are likely implemented in IEEE format with 53 bits of precision, a 32-bit int value can be converted to double with no loss of precision, so you can use the fabs() function to get the absolute value of a 32-bit int value in one call:
7.12.7.2 The fabs functions
Synopsis
#include <math.h>
double fabs(double x);
float fabsf(float x);
long double fabsl(long double x);
The fabs functions compute the absolute value of a floating-point
number x.
So your code would be:
#include <stdio.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
printf("absValue = %u\n", (unsigned) fabs((double) u));
return 0;
}
Note that in (unsigned) fabs((double) u), casting u to double is not strictly necessary, as the int value will be implicitly converted to a double because of the double fabs(double) function prototype from stdlib.h. But the cast back to unsigned is exremely necessary to pass the unsigned int value you want to pass to printf().
You could also do this:
#include <stdio.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
unsigned int absValue = fabs(u);
printf("absValue = %u\n", absValue);
return 0;
}
That works because unsigned int absValue is explicitly an unsigned int.
Also, on modern CPUs, conversion between int and double is usually done by a single relatively fast instruction.
How to write absolute value in c?
The shortest solution :
#include <stdlib.h>
printf("absValue = %d\n", abs(u)); // clear and concise - yet see below
Both printf("%d\n", abs(u)); and printf("%u\n", (unsigned)((u<0)?-u:u)); suffer the same problem: undefined behavior (UB) when n == INT_MIN1. The signed negation of INT_MIN is the UB.
At least abs(u) is clear, unlike (unsigned)((u<0)?-u:u).
To print the absolute value of an int, code could negate negative values with:
(-1 - n) + 1u or
-(unsigned)n or
0u - n
... and end up with an unsigned.2
I'd go for the simplest when a full range |int| is sought.
printf("absValue = %u\n", n < 0 ? 0u - n : (unsigned) n);
Using long, long long or double poses their own troubles and portability. None warranted here.
1 when int is 2's complement encoded - very common.
2 C specified UINT_MAX >= INT_MAX. In the very rare implementations today, INT_MAX == INT_MAX is possible and code needs to resort to a wider type when int is non 2's complement.
printf doesn't convert the strings, but rather expects them converted. I would generally prefer to use the standard abs function which is declared in stdlib.h. This uses strtol to convert an argument to a long then convert that to an int. Nota bene, that, for example, if your machine uses two's-complements, calling abs(INT_MIN) produces undefined behaviour and should be dealt with. (Edited: error detection now complies with non-POSIX systems; see comments.)
#include <stdio.h> /* perror, printf */
#include <stdlib.h> /* strtol, abs */
#include <limits.h> /* INT_MIN, INT_MAX */
#include <errno.h> /* errno, ERANGE */
int main(int argc, char *argv[]) {
int u;
long input;
char *end;
/* Require one argument. */
if(argc != 2) return printf("Usage <number>\n"), EXIT_SUCCESS;
/* `input` is converted from `argv[1]`, if it's 0, check that it actually
read 0; check to see garbage characters at the end; check to see if the
`input` is a) less then `INT_MIN`; b) also if `-INT_MAX < 0`, check that
it is not lower than this value, because that will lead to undefined
`abs`; c) more then `INT_MAX` -> if so, set `ERRNO` and enter the if. */
if( ((input = strtol(argv[1], &end, 0)) == 0 && end == argv[1])
|| (*end != '\0' && (errno = EILSEQ, 1))
|| ((input < INT_MIN || (-INT_MAX < 0 && input < -INT_MAX)
|| input > INT_MAX) && (errno = ERANGE, 1)) )
return perror("Input"), EXIT_FAILURE;
/* We are pretty sure this cast is safe, now: `int abs(int)`. */
u = abs((int)input);
printf("absValue(%ld) = %d\n", input, u);
return EXIT_SUCCESS;
}
Checking edge cases,
bin/abs 2147483647
absValue(2147483647) = 2147483647
bin/abs 2147483648
Input: Result too large
bin/abs -2147483648
Input: Result too large
bin/abs -2147483647
absValue(-2147483647) = 2147483647
bin/abs
Usage <number>
bin/abs 0x10
absValue(16) = 16
bin/abs asdf
Input: Invalid argument
bin/abs 1a
Input: Illegal byte sequence
this is a function to get the absolute value of a number without using abs() function.
int abs_value(int *a){
return *a < 0 ? -*a: *a;
}
If you want to get the absolute difference between two numbers, here's how:
int abs_diff (int *a, int*b) {
return *a > *b ? *a - *b : *b - *a;
}

C Program - About Sizeof and Constant Used Together

Below is the code I am having issues with. I understand constants and believe I understand the sizeof function but must be missing something. Here is what I have tried to do to solve on my own:
- printf statement with TOTAL_ELEMENTS as the %d - it returns 7
- printf statement of TOTAL_ELEMENTS - 2 - it returns 5 (as expected)
- substitute 5 in the for loop - loop runs correctly
- initialize a global int variable of any name and set it equal to (sizeof(array) / sizeof(array[0])). Then used the variable in the for loop where TOTAL_ELEMENTS would go - again the loop runs correctly.
So (at least in my head), it has to be something involving both the constant and the sizeof function - I'm positive the array/array[0] also plays a part but through testing and substitution I can't figure out what the issue is. I have read up on the sizeof function as well as constants to no avail. I have tried searching but have gotten no where as I'm not fully certain what I'm searching for. I don't necessarily need answers but if someone could point me in the right direction it would be much appreciated. Thank you in advance.
#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]);
return 0;
}
This issue is not related to sizeof. this is because of the comparing signed with unsigned value. In your code , (TOTAL_ELEMENTS-2) has an unsigned value , but d is a signed variable. therefore , for condition will compare 5 with 0xFFFFFFFF and 5 is less than 0xFFFFFFFF then it is false always!
For example :
int main()
{
int d;
unsigned int e = 5;
for (d = -1; d <= e; d++)
printf("%d\n", array[d + 1]);
return 0;
}
It do not print any things! , same as your code.

comparison operation [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Unsigned and signed comparison
A riddle (in C)
#include<stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main()
{
int d = -1;
if (d < TOTAL_ELEMENTS)
printf("of course -1 is less than %d",TOTAL_ELEMENTS);
else
printf("how on earth");
return 0;
}
answer is:::Output of the above program is : how on earth
When you perform mixed signed vs. unsigned comparison (where signed type is not larger than unsigned one), the comparison is performed in unsigned domain, i.e. the signed operand is implicitly converted to unsigned type.
In your case TOTAL_ELEMENTS has type size_t, which is unsigned. That means that your d is also implicitly converted to size_t type. So, your d < TOTAL_ELEMENTS is actually interpreted as (size_t) d < TOTAL_ELEMENTS or (size_t) -1 < TOTAL_ELEMENTS.
(size_t) -1 is an extremely large positive value. It is actually the largest possible value of type size_t. Hence the result you get.
In your case you apparently want a signed comparison. For that you have to explicitly convert the unsigned value to signed type (paying close attention not to cause overflow). For example, this will work "as expected"
if (d < (int) TOTAL_ELEMENTS)
...
This is because sizeof_t is mapped to an unsigned long type, so -1 becomes 0xFFFFFFFFFFFFFFFF, a rather large positive integer. Try this:
#include<stdio.h>
#define TOTAL_ELEMENTS(a) ((int)(sizeof((a))/sizeof(*(a))))
int array[] = {23,34,12,17,204,99,16};
int main() {
int d = -1;
if (d < TOTAL_ELEMENTS(array)) {
printf("of course -1 is less than %d",TOTAL_ELEMENTS(array));
} else {
printf("how on earth");
}
return 0;
}
Note how I re-wrote your macro to reference array as its parameter, and added a cast to int to ensure that comparing to -1 would bring an expected result.

c code output unexpected/expected behaviour

what is wrong with this code ? can anyone explain ?
#include <stdio.h>
#include <malloc.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main()
{
int num;
int d;
int size = TOTAL_ELEMENTS -2;
printf("%d\n",(TOTAL_ELEMENTS-2));
for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);
return 0;
}
when i print it gives 5, but inside for loop what is happening ?
The sizeof operator returns a value of type size_t, which is an unsigned value. In your for loop condition test:
d <= (TOTAL_ELEMENTS-2)
you are comparing a signed value (d) with an unsigned value (TOTAL_ELEMENTS-2). This is usually a warning condition, and you should turn up the warning level on your compiler so you'll properly get a warning message.
The compiler can only generate code for either a signed or an unsigned comparison, and in this case the comparison is unsigned. The integer value in d is converted to an unsigned value, which on a 2's complement architecture ends up being 0xFFFFFFFF or similar. This is not less than your TOTAL_ELEMENTS-2 value, so the comparison is false.
You're starting the loop by setting d = -1, it should be d = 0. So for the first element you're reading random bits of memory.
If you fix that, then you can change your printf to be
printf("%d\n",array[d]);
As you've also marked this as homework, I'd advise also take a look at your loop terminating condition.

Resources