type conversion between pointers. Wrong print - c

The program is written in language C.
We ascertain that the values contained in the variables i and f have the same sequence of bits. Now go to line 63 of the program.
I create the variables ui and uf of type unsigned int.
I assign to ui the value of i converted to unsigned int.
I assign to uf the value of f converted to unsigned int.
MY QUESTION is: why when I print the contents of ui and uf I get two different values? (ui = 3281948672
uf = 4294966979). Considering that the values contained in i and f have the same binary representation, shouldn't the printing of ui and uf give me the same value? That is 3281948672.
it's strange, because when I print the contents of *ipi and *ipf, which point to i and f, they give me the same result (*ipi = 3281948672
*ipf = 3281948672). HELP ME!
Here is the source code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
float f = -317.125;
int i = -1013018624;
printf("Value : %f %d\n",f,i);
printf("Indexs: %p %p\n",&f,&i);
if(i == f)
{
printf("equals\n");
}
else
{
printf("Differents\n");
}
float* pf = &f;
int* pi = &i;
printf("float *pt %p, int *pi %p\n",pf,pi);
if(*pi == *pf)
{
printf("*pt and *pi equals\n");
}
else
{
printf("differents\n");
}
void* vpf = &f;
void* vpi = &i;
unsigned int *ipf = (unsigned int *)vpf;
unsigned int *ipi = (unsigned int *)vpi;
if(*ipf == *ipi)
{
printf("*ipf e *ipi are equals why the bits contained in the pointed memory areas are the same\n");
}
else
{
printf("differents\n");
}
printf("*ipi = %u\n",*ipi);
printf("*ipf = %u\n",*ipf);
printf("*ipi in hex = %08X\n",*ipi);
printf("*ipf in hex = %08X\n\n\n",*ipf);
unsigned int ui,uf;
ui = (unsigned int)i;
uf = (unsigned int)f;
printf("ui = %u\n",ui);
printf("uf = %u",uf);
return 0;
}

In C, conversion from a floating point type to an integral type is not a bit-for-bit conversion. So, even though i and f are bit-for-bit identical, they are not converted to unsigned int in an identical way. What you see is expected behavior.

Related

Question about converting `void *` to `int` in C

I'm trying to pick my C skills again. I want to sum a sequence in different threads, each thread would return a pointer of the sum of a part of the sequence. However, when I tried to convert the void* type value local_sum to int, problem occurred.
I tried to convert with sum += *(int*)local_sum;, a segment error occurred and I got Process finished with exit code 11.
I found that if I use sum += (int)local_sum;, it would be okay. But I couldn't convince myself: shouldn't local_sum be a void *? Why it can be converted to int with (int)local_sum?
I'm so grateful it you could answer the problem.
The part that sum each process's return value is here:
int sum = 0;
for (int i = 0; i < NUM_THREADS; i ++) {
void * local_sum;
pthread_join(count_threads[i], (&local_sum));
sum += (int)local_sum;
}
The function of a thread is here:
void * count_thr(void *arg) {
int terminal = ARRAY_SIZE / NUM_THREADS;
int sum = 0;
for (int i = 0; i < terminal; i ++) {
sum += *((int*)arg + i);
}
return (void*)sum;
}
You're returning the value of int sum by setting a void * address to it. In this case, the address is not valid. But, if you keep that in mind and get the value of sum by casting a void * to int it will work.
void * is used this way sometimes to return either a value (e.g. int) or an address to something (e.g. struct).
To illustrate this:
int a = 5;
void *p = (void *)a;
int b = (int)p;
a, p, and b all have a value of 5. p does not point to a valid address. Trying to dereference p would result in undefined behavior:
b = *(int *)p; // Undefined Behavior!
Consider the following program:
#include <limits.h>
#include <stdio.h>
int main(void)
{
int a, b;
void *p;
a = 5;
p = (void *)a;
b = (int)p;
printf("%d %p %d\n", a, p, b);
a = INT_MAX;
p = (void *)a + 1;
b = (int)p;
printf("%d %p %d\n", a, p, b);
return 0;
}
When compiled, I get the following warnings:
$ gcc main.c -o main.exe
main.c: In function ‘main’:
main.c:9:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
p = (void *)a;
^
main.c:10:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
b = (int)p;
...
A warning is issued because, as pointed out by #Gerhardh, the sizeof(int) and the sizeof(void *) may be different. You may suffer data loss if the value of the void * exceeds the maximum value a int can hold.
Output
$ ./main.exe
5 0x5 5
2147483647 0x80000000 -2147483648
You can't do *(int*)local_sum because local_sum is not an int* cast to void*. local_sum is an int cast to void*. It is a number reinterpreted as an address, but only for transfer purposes, because pthread_exit only allows you to return a void*, not an int and because the standard explicitly allows implementation-defined conversion (6.3.2.3p5, 6.3.2.3p6) between integers and numbers as long as the values fit (if they don't then, UB). If you return, e.g., 0x42, it is highly unlikely there's anything at address 0x42, so you should forget about dereferencing it and instead you should convert it back to an integer ASAP, either with (int)local_sum; or perhaps better with (int)(intptr_t)local_sum; (though intptr_t isn't guaranteed to exist) or (perhaps best) with (int)(intmax_t)local_sum; so as to avoid possible compiler warnings about converting to an integer of a different size on LP64 platforms.
A secure and portable solution could be the use of an union:
union void_cast {
void* ptr;
int value;
};
Then for example you can safely reinterpret a void* pointer with:
int VOID_TO_INT(void* ptr) {
union void_cast u;
u.ptr = ptr;
return u.value;
}
void* INT_TO_VOID(int value) {
union void_cast u;
u.value = value;
return u.ptr;
}
So your code can be changed to:
sum += VOID_TO_INT(local_sum);

C ,help me in understanding this ASCII prob

This code will print:
s = 1, i = 65537, f = 65537.000000, c = 1
I need help in understanding why is it printing c=1.
The code:
#include <stdio.h> // Standard input-output library
#include <stdlib.h> // Standard general utilities library
int main(void) {
int i = 65537;
unsigned short s = (unsigned short)i;
float f = (float)i;
char c = (char)i;
printf("s = %u, i = %d, f = %f, c = %d\n", s,i,f,c);
system("PAUSE");
return (0);
}
If to output the variable i in hex representation like this
#include <stdio.h>
int main(void)
{
int i = 65537;
printf( "%#0x\n", i );
return 0;
}
then you will see that it looks like
0x10001
Type char always occupies one byte. Thus in this assignment
char c = (char)i;
one byte of the object i
0x10001
^^
is stored in the variable c.
In the printf statement in your program
printf("s = %u, i = %d, f = %f, c = %d\n", s,i,f,c);
^^^^^^
it is outputted using type specifier %d. So its internal value is outputted as an integer of type int.
Usually objects of the type unsigned short occupy two bytes. Thus in this assignment
unsigned short s = (unsigned short)i;
the value in the first two bytes of object i
0x10001
^^^^
will be assigned to variable s.
So c and s the both will have value 1.

casting unsigned char to char would result in different binary representations?

I think the title is pretty self explanatory but basically what I'm saying is that, if I have the following instruction:
a = (char) b;
knowing that a's type is char and b's is unsigned char, can that instruction result in making a and b have different binary representations?
The type char can be either signed or unsigned. Char types have no padding, so all bits are value bits.
If char is unsigned, then the value bits of a will be the same as those of b.
If char is signed, then...
if the value of b is representable by char, the common value bits of a and b will the same.
otherwise, the conversion from unrepresentable unsigned char value to char results in an implementation-defined result.
The answer in general, is no, there is no difference. Here you can test it yourself. Just supply the respective values for 'a' and 'b'
#include <stdio.h>
#include <string.h>
const char *byte_to_binary(int x)
{
static char b[9];
b[0] = '\0';
int z;
for (z = 128; z > 0; z >>= 1)
strcat(b, ((x & z) == z) ? "1" : "0");
}
return b;
}
int main(void) {
unsigned char b = -7;
char a = -7;
printf("1. %s\n", byte_to_binary(a));
a = (char) b;
printf("2. %s\n", byte_to_binary(a));
return 0;
}

Two's complement and loss of information in C

I want do the two's complement of a float data.
unsigned long Temperature ;
Temperature = (~(unsigned long)(564.48))+1;
But the problem is that the cast loses information, 564 instead of 564.48.
Can i do the two's complement without a loss of information?
That is a very weird thing to do; floating-point numbers are not stored as 2s complement, so it doesn't make a lot of sense.
Anyway, you can perhaps use the good old union trick:
union {
float real;
unsigned long integer;
} tmp = { 564.48 };
tmp.integer = ~tmp.integer + 1;
printf("I got %f\n", tmp.real);
When I tried it (on ideone) it printed:
I got -0.007412
Note that this relies on unspecified behavior, so it's possible it might break if your compiler does not implement the access in the most straight-forward manner. This is distinct form undefined behavior (which would make the code invalid), but still not optimal. Someone did tell me that newer standards make it clearer, but I've not found an exact reference so ... consider yourself warned.
You can't use ~ over floats (it must be an integer type):
#include <stdio.h>
void print_binary(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char *) ptr;
unsigned char byte;
int i, j;
for (i = size - 1; i >= 0; i--) {
for (j = 7; j >= 0; j--) {
byte = b[i] & (1 << j);
byte >>= j;
printf("%u", byte);
}
}
printf("\n");
}
int main(void)
{
float f = 564.48f;
char *p = (char *)&f;
size_t i;
print_binary(sizeof(f), &f);
for (i = 0; i < sizeof(float); i++) {
p[i] = ~p[i];
}
print_binary(sizeof(f), &f);
f += 1.f;
return 0;
}
Output:
01000100000011010001111010111000
10111011111100101110000101000111
Of course print_binary is there for test the result, remove it, and (as pointed out by #barakmanos) print_binary assumes little endian, the rest of the code is not affected by endiannes:
#include <stdio.h>
int main(void)
{
float f = 564.48f;
char *p = (char *)&f;
size_t i;
for (i = 0; i < sizeof(float); i++) {
p[i] = ~p[i];
}
f += 1.f;
return 0;
}
Casting a floating-point value to an integer value changes the "bit contents" of that value.
In order to perform two's complement on the "bit contents" of a floating-point value:
float f = 564.48f;
unsigned long Temperature = ~*(unsigned long*)&f+1;
Make sure that sizeof(long) == sizeof(float), or use double instead of float.

Check if char array[] contains int, float or double value and store value to respective data type

In C programming, how do i check whether char array[] contains int, float or double value and also store the value using respective data type?
Example:
If the char array[] contains 100 - its int value and should be store in int a.
if the char array contains 10000.01 its float value and should be stored in float b.
The only way you can store mixed types in an array is to have an array of pointers.
You'd need to use a struct or a union to store each one too like so:
#define TYPE_INT 1
#define TYPE_FLOAT 2
#define TYPE_STRING 3
typedef struct {
int type;
void *ptr;
} object;
object* mkobject( int type, void * data ){
object * obj = (object*)malloc(COUNT*sizeof(object))
obj->type = type;
obj->ptr = data;
return obj;
}
No using the above you can store type information
void * intdup( int original ) {
int * copy = (int*) malloc(1*sizeof(int));
*copy = original;
return (void*) copy;
}
void * floatdup( float original ) {
float * copy = (float*) malloc(1*sizeof(float));
*copy = original;
return (void*) copy;
}
int COUNT = 3;
objects** objectlist = (object**)malloc(COUNT*sizeof(object*))
// -- add things to the list
int a_number = 2243;
float a_float = 1.24;
char* a_string = "hello world";
objectlist[0] = mkobject( TYPE_STRING, strdup(a_string) );
objectlist[1] = mkobject( TYPE_INT, intdup(a_number) );
objectlist[2] = mkobject( TYPE_FLOAT, intdup(a_float) );
// iterate through a list
for ( int x = 0; x < COUNT; x++ ){
switch( objectlist[x]->type ){
case TYPE_STRING:
printf("string [%s]\n",(char*) objectlist[x]->ptr );
break;
case TYPE_FLOAT:
printf("float [%f]\n", *(float*) objectlist[x]->ptr );
break;
case TYPE_INT:
printf("int [%d]\n", *(int*) objectlist[x]->ptr );
break;
default;
printf("unintialized object\n");
break;
}
}
In C, unlike in other languages, you have to define the type of the variable at compile time. So if you have a char variable (or char array), you have char and not int and not float and not double.
Since it is not possible to define variables types at run-time, you would still need to have variables of the correct data type defined at compile time. If that is not a problem, you could probably scan the string and look for decimal separators to determine if it is a float or integer value. But perhaps not the most robust method :-)
I think you want to use a union (from my understanding of your answer).
union {
char a[4];
float b;
int c;
} dude;
// ...
union dude woah;
woah.a = "abc";
puts(a);
woah.b = 4.3;
printf("%f\n", woah.b);
woah.c = 456;
printf("%d\n", woah.c);
If you are storing a value like:
"100.04"
in the char array or something like that you can do this to check if the number has a decimal or not:
double check = atof(theChar);
if (check % 1 > 0) {
//It's a real number
}
else {
//It's more specifically an integer
}
If that is what you mean. Your question is a little unclear to me.
Although, this isn't really type checking, it is just testing where the thing has a decimal or not... Like others have said you can't do it because the char* is defined during compilation not during run time and can't be change.
Assume the number is a floating point number and use strtod().
If the conversion worked, the number can be integer. Check limits and closeness to a proper integer and convert again if ok.
Pseudo-code
char *input = "42.24";
char *err;
errno = 0;
double x = strtod(input, &err);
if (errno == 0) {
/* it's (probably) a floating point value */
if ((INT_MIN <= x) && (x <= INT_MAX)) {
if (fabs(x - (int)x) < 0.00000001) {
/* It's an integer */
int i = x;
}
}
} else {
/* deal with error */
}

Resources