How to convert signed to unsigned char in OpenCL? - c

I have a signed char in OpenCL that I need to convert to a unsigned char.

The OpenCL standard defines explicit conversion functions for all the built-in scalar and vector types. So you can do something like this:
char signed_val = 10;
uchar unsigned_val = convert_uchar(signed_val);

C-like casting should work. The only difference is that you use cl_ types. But these are equivalent to the C types.
For example, to convert signed to unsigned char:
cl_char c = 0xF;
cl_uchar uc = c;
To convert a pointer to signed char to pointer to unsigned char:
cl_char* cArr = // Points to char array
cl_uchar* ucArr = ( cl_uchar* ) cArr; // Access char array as uchar array

Related

Is it unsafe to pass an unsigned long to a function which uses a long?

Foreword: I am not allowed to use any functions from the C library
I have this function:
char *to_base(long nbr, char *base)
{
static char buffer[50];
char *ptr;
int base_len;
ptr = &buffer[49];
*ptr = 0;
base_len = ft_strlen(base);
while (nbr != 0)
{
*--ptr = base[nbr % base_len];
nbr /= base_len;
}
return (ptr);
}
As we can see it takes a long. In my program I have an unsigned long which I have to translate into its hexadecimal value. Is it unsafe to pass the unsigned long at this function ? If yes how can I make it work ?
EDIT :
Here is how I am currently using it:
unsigned long val;
char *hexa;
val = (unsigned long)va_arg(*list, void *);
hexa = to_base(val, "0123456789abcdef");
Is it unsafe to pass the unsigned long at this function ?
It's "safe", as in the program will not format your hard drive or start another world war.
Passed function arguments are converted to the argument type. The unsigned value will be converted to a signed one. All architectures today use twos-complement, it's easy to predict the result. Your compiler should document the behavior, ex. in gcc implementation defined beahvior:
The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).
For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.
"reduced modulo 2^N" - basically 2^N is subtracted until the value is within range. So if you have 32-bit longs and have (long)(unsigned long)4294967196ul so you subtract 2^32 from the value and it's equal to (long)-100.
If yes how can I make it work ?
Properly handle negative numbers.
And write a separate function for unsigned and signed numbers.
Also (unsigned long)va_arg(*list, void *); is casting a void* pointer value to an unsigned long (?). Most probably you want va_arg(list, unsigned long) - to take unsigned long from arguments.

C "Error: Invalid initializer"

the following short code snippet results in a invalid initializer error, and as a beginner in C, I do not understand why.
unsigned char MES[] = { 0x00, .... };
unsigned char *in[] = &MES;
Is this not the correct way to do it?
&MES is a pointer to an array of unsigned char.
in is an array of pointers to unsigned char.
Try instead :
unsigned char (*in)[] = &MES;
which makes in also a pointer to an array of unsigned char.
I think that what you are trying to achieve is the following:
unsigned char MES[] = { 0x00 };
unsigned char *in = MES;
qualifying in as an array (whose size is unknown) as follow
unsigned char (*in2)[] = &MES;
is not going to add valuable information to it aside that it has a finite size (which is true for any data) and if you print in and in2
printf ("%lx\n", (long unsigned int) in);
printf ("%lx\n", (long unsigned int) in2);
the value shall be the same.
Don't confuse the position of the data with the position of its reference.
Using &MES is like trying to read the position in memory where the position of the array is written. But this does not exist.
Consider the counterexample:
void *reference_to_memoryarea = malloc(3);
void **reference_to_the_reference = &reference_to_memoryarea;
Here the position exists and has a position in memory, where it is stored. And you can write into *reference_to_the_reference and generate a good leak

Trying to Assign Pointer out of a struct to a two-dimensional array

have an assignment where I should use the following struct:
typedef struct natset{
unsigned long min;
unsigned int size;
unsigned char* bits;
}natset_t;
Now I have to assign that pointer to the following two-dimensional array of unsigned chars:
unsigned char bArrayRoll[7][byteNum];
Which I have tried doing like so:
unsigned long min = 20;
unsigned int size = 20;
unsigned char bArrayRoll[7][byteNum];
natset_t newNatset;
newNatset.min = min;
newNatset.size = size;
newNatset.bits = &bArrayRoll;
Variations of that newNatset.bits which I have tried include:
newNatset.bits = bArrayRoll;
newNatset.bits* = &bArrayRoll;
However, the compiler either returns "Assignment from incompatible pointer type" or "Initialization from incompatible pointer type".
How can I assign the bits pointer to this array correctly?
newNatset.bits* = &bArrayRoll;
You are trying to multiply newNatset.bits with the address of bArrayRoll, this is undefined behavior.
newNatset.bits = bArrayRoll;
This one here is trying to assign unsigned char (*)[byteNum] to unsigned char* which is again something about which compiler complained. Types are incompatible clearly.
Correct one would be (correct one as per the compiler)
newNatset.bits = bArrayRoll[0];
wouldn't it have to be: newNatset.bits = bArrayRoll[0][0]?
This is once again a type incompatible assignment. You are assigning unsigned char to unsigned char*. You can do this though,
newNatset.bits = &bArrayRoll[0][0];
Trying to Assign Pointer out of a struct to a two-dimensional array? (The thing you wanted).
Then you need to do this,
unsigned char (*p)[byteNum] = bArrayRoll;
but in the structure you have declared bits to be of type unsigned char* not of type unsigned char (*)[byteNum].
Well if you didn't understand what happened when we assigned in the last case and how did the types match - then here is the key idea.
The 2d array decays into the pointer to the first element - which is a single dimensional array of byteNum unsigned characters. Now we are assigning it to p which is again
unsigned char (*)[byteNum]
^ ^
1 2
\-----------/
3
Pointer to (1) an array of bytenum (2) unsigned characters (3).

C Character from literal Splint warns of incompatible types

I have a program that uses unsigned chars to represent integers with a small range. I find myself needing to clear them to 0 in several different parts of the program, I have also recently started using splint and apparently:
unsigned char c = 0;
gives the warning:
Variable c initialized to type int, expects unsigned char: 0
Types are incompatible.
As there is no suffix for a literal char, How is it best to resolve this? I think I have a few options:
1: Ignore the warning.
2: Cast every time:
unsigned char c = (unsigned char)0;
3: Make a var to cut down the length of the code:
unsigned char uc_0 = (unsigned char)0;
unsigned char c = uc_0;
4: A function:
static inline unsigned char uchar(int in)
{
return (unsigned char)in;
}
unsigned char c = uchar(0);
splint has an option +charint that will treat char int as interchangeable.
You can ignore the warnings and use
unsigned char = 0;
In many cases when there is integer operation in order to save memory instead of using int which obviously consumes extra memory than char people do make use of unsigned char.
unsigned char i = 10;
unsigned char j = 1;
unsigned char k = i +j;
printf("%d",k);

Different pointer types for the same address

I am relative new to programming so I apologize if my question is basic.
Situation:
I have several float values and an array of pointers to each value. Ex:
float nr1=1.15;
float nr2=2.30;
float nr3=23.34;
....
float * my_address_array[3];
my_address_array[0] = &nr1;
my_address_array[1] = &nr2;
my_address_array[2] = &nr3;
To access one element, I can use:
float temp_value;
float ** ptr_value;
...
ptr_value = &my_address_array[0];
temp_value = **( ptr_value+0); // copy nr1 to temp
temp_value = **( ptr_value+1); // copy nr2 to temp
temp_value = **( ptr_value+2); // copy nr3 to temp
So far so good. On my system float occupies 32 bits (8051 microcontroller). I need to take one float number and separate it into four 8 bit variables. Example for nr2:
My attempt was:
unsigned char storage1;
unsigned char storage2;
unsigned char storage3;
unsigned char storage4;
...
storage1 =(unsigned char) ((**( ptr_value+1)) >> 24) ;
storage2 =(unsigned char) ((**( ptr_value+1)) >> 16) ;
storage3 =(unsigned char) ((**( ptr_value+1)) >> 8) ;
storage4 =(unsigned char) ((**( ptr_value+1)) & 0xff) ;
I get bad operand type. It seems that I cannot use bit shift operations with float numbers (at least google sais that). I can add a new pointer, as in:
char ** ptr_char_value;
...
ptr_char_value = &my_address_array[0]; // generates warning
storage1 = (*(*( ptr_char_value+1)+0));
storage2 = (*(*( ptr_char_value+1)+1));
storage3 = (*(*( ptr_char_value+1)+2));
storage4 = (*(*( ptr_char_value+1)+3));
I do get a warning (which is fair) that I am using a char type pointer for a float value. I am also not sure how reliable this is. Can anyone advise a better solution?
Thank you!
Edit: The code is for a 8051 microcontroller. I would like to make it as fast/optimal as possible.
with this, you are getting pointer to pointer to value
ptr_char_value = &my_address_array[0];
I don't understand how this should work.
It would be better to use pointer to float directly. Cast it to char array and get separate bytes.
char * ptr_char_value = (char *)(my_address_array[0]);
storage1 = ptr_char_value[0];
storage2 = ptr_char_value[1];
storage3 = ptr_char_value[2];
storage4 = ptr_char_value[3];
EDIT:
It is also question if you realy need array of pointers to floats. It is possible to have struct, cast it to array of bytes and use these bytes directly for something.
struct my_data_type {
float nr1;
float nr2;
float nr3;
}
struct my_data_type my_data;
my_data.nr1 = 1.15;
my_data.nr2 = 4.75;
my_data.nr3 = 8.95;
char * ptr_char_value = (char *)&my_data;
// nr1
storage1 = ptr_char_value[0];
...
// nr2
storage5 = ptr_char_value[4];
...
// nr3
storage9 = ptr_char_value[8];
...
try this. You should type cast before you can shift the data. Include stdint.h
storage1 = (uint8_t) ((((uint32_t)**( ptr_value+1))) >> 24) & 0xFF );
Let's begin with the title:
Different pointer types for the same address
That's code smell. In C, aliasing objects through an incompatible pointer type results in undefined behavior, unless the incompatible aliasing type is (qualified or unqualified, signed or unsigned) character type.
More precisely, an object of type cv-qualified or unqualified T may only be accessed through a pointer to qualified or unqualified T. Additionally, if T is an integral type, then accessing via its (qualified or unqualified) signed or unsigned counterpart is permitted as well.
This is colloquially called the "strict aliasing rule".
Hence, you can't do
float f;
*(int *)&f
even if sizeof(float) == sizeof(int).
The possible solutions:
Use memcpy(), like this (preferred):
float f = 3.14;
int i;
memcpy(&i, &f, sizeof f);
Use a union (C99 only – this is UB too in C89…):
union {
float f;
int i;
} pun = { .f = 3.14 };
printf("%d\n", pun.i);
Why do you want to separate float in 4 variables?
That don't make any sense because of how float is represented in computer.
First bit S is sing, 0 for positive 1 for negative numbers. Then 8 bits of exponent and remaining 23 for mantissa.
So, there is nothing useful you can do with 8bit parts, because they are on their own meaningless.

Resources