I need to copy the data from 2 char (8 bit long) to a single short (16 bit long). I tried two different ways, but can't get it to work.
void char2short(char* pchar, short* pshort)
{
memcpy(pshort , pchar + 1 , 1);
memcpy(pshort + 1, pchar , 1);
}
And the other one:
void char2short(char* pchar, short* pshort)
{
short aux;
aux = ((*pchar & 0x00FF) << 8) | ((*(pchar+1) & 0xFF00) >> 8);
*pshort = aux;
}
#include <stdio.h>
void char2short(unsigned char* pchar, unsigned short* pshort)
{
*pshort = (pchar[0] << 8) | pchar[1];
}
int main()
{
unsigned char test[2];
unsigned short result = 0;
test[0] = 0xAB;
test[1] = 0xCD;
char2short(test, &result);
printf("%#X\n",result);
return 0;
}
this will do the job.
Assuming pchar is an array that contains your 2 chars, how about:
*pshort = (uint16_t)(((unsigned int)pchar[0]) |
(((unsigned int)pchar[1])<<8));
P.S. This work for little endianess.
Others didn't explain why your code didn't work, so I'll take a quick stab at it:
memcpy(pshort , pchar + 1 , 1);
memcpy(pshort + 1, pchar , 1);
Adding to a pointer TYPE * p moves the pointer by increments of sizeof( TYPE ) (so it does point at the next element, remember this is only defined if inside an array). So while pchar + 1 is correct, pshort + 1 is not (as it's addressing the next short).
aux = ((*pchar & 0x00FF) << 8) | ((*(pchar+1) & 0xFF00) >> 8);
Errr.... the right hand side is broken in more ways than one. First, *(pchar+1) is a char, and & 0xFF00 on a char will always yield 0 (because a char is only 8 bits to begin with, at least on contemporary machines...). And then you shift that 8 bits to the right...?
And just in case you weren't aware of it, if you hadn't used 0x00FF on the left hand side (promoting *pchar to the width of the right-hand operand) but (char-sized) 0xFF, the result of that operation would still be of type char, and shifting that 8 bits to the left doesn't make much sense either (as the type doesn't get expanded magically).
Another way to go about this not mentioned yet is the union:
#include <stdio.h>
struct chars_t
{
// could also go for char[2] here,
// whichever makes more sense semantically...
char first;
char second;
};
union combo_t
{
// elements of a union share the memory, i.e.
// reside at the same address, not consecutive ones
short shrt;
struct chars_t chrs;
};
int main()
{
union combo_t x;
x.chrs.first = 0x01;
x.chrs.second = 0x02;
printf( "%x", x.shrt );
return 0;
}
If you're using this in a larger context, beware of struct padding.
When doing bitwise operations, use robust code with real fixed-size integers, of known signedness. This will prevent you from writing bugs related to implicit type conversions, causing unintended signedness. The char type is particularly dangerous, since it has implementation-defined signedness. It should never be used for storing numbers.
#include <stdint.h>
void char2short(const uint8_t* pchar, uint16_t* pshort)
{
*pshort = ((uint16_t)pchar[0] << 8) | (uint16_t)pchar[1];
}
Related
I would like to make a int varibale out of a char array in C.
The char array looks like this:
buffer[0] = 0xcf
buffer[1] = 0x04
buffer[2] = 0x00
buffer[3] = 0x00
The shifting looks like this
x = (buffer[1] << 8 )| (buffer[0] << 0) ;
After that x looks like this:
x = 0xffff04cf
Right now everthing would be fine, if the first two bytes wouldn't be ff.
If I try this line
x = (buffer[3] << 24 )| (buffer[2] << 16)| (buffer[1] << 8)| (buffer[0] << 0) ;
it still looks
x = 0xffff04cf
Even when I try to shift in the zeros before or after I shift in 04cf it looks still the same.
Is this the rigth idea to it or what am I doing wrong?
The issue is that you declared buffer by means of a signed type, probably (signed) char. When applying operator <<, integral promotions will be performed, and as the value 0xcf in an 8-bit signed type represents a negative value (i.e. -49), it will remain a negative value (yet represented by more bits, i.e. 0xffffffcf). Note that -1 is represented as 0xFFFFFFFF and vice versa.
To overcome this issue, simply define buffer as
unsigned char buffer[4]
And if you weren't allowed to change the data type of buffer, you could write...
unsigned x = ( (unsigned char)buffer[0] << 8 )| ((unsigned char)buffer[1] << 4) ;
For tasks like this I like using unions, for example:
union tag_int_chars {
char buffer[sizeof(int32_t)];
int32_t value;
} int_chars;
int_chars.value = 0x01234567;
int_chars.buffer[0] = 0xff;
This will automate the memory overlay without the need to shift. Set the value of the int and voila the chars have changed, change a char value and voila the int has changed.
The example will leave the int value = 0x012345ff on a little endian machine.
Another easy way is to use memcpy():
#include <string.h>
char buffer[sizeof(int32_t)];
int32_t value;
memcpy(&value, buffer, sizeof(int32_t)); // chars to int
memcpy(buffer, &value, sizeof(int32_t)); // int to chars
I'm writing C implementation of Conway's Game of Life and pretty much done with the code, but I'm wondering what is the most efficient way to storage the net in the program.
The net is two dimensional and stores whether cell (x, y) is alive (1) or dead (0). Currently I'm doing it with unsigned char like that:
struct:
typedef struct {
int rows;
int cols;
unsigned char *vec;
} net_t;
allocation:
n->vec = calloc( n->rows * n->cols, sizeof(unsigned char) );
filling:
i = ( n->cols * (x - 1) ) + (y - 1);
n->vec[i] = 1;
searching:
if( n->vec[i] == 1 )
but I don't really need 0-255 values - I only need 0 - 1, so I'm feeling that doing it like that is a waste of space, but as far as I know 8-bit char is the smallest type in C.
Is there any way to do it better?
Thanks!
The smallest declarable / addressable unit of memory you can address/use is a single byte, implemented as unsigned char in your case.
If you want to really save on space, you could make use of masking off individual bits in a character, or using bit fields via a union. The trade-off will be that your code will execute a bit slower, and will certainly be more complicated.
#include <stdio.h>
union both {
struct {
unsigned char b0: 1;
unsigned char b1: 1;
unsigned char b2: 1;
unsigned char b3: 1;
unsigned char b4: 1;
unsigned char b5: 1;
unsigned char b6: 1;
unsigned char b7: 1;
} bits;
unsigned char byte;
};
int main ( ) {
union both var;
var.byte = 0xAA;
if ( var.bits.b0 ) {
printf("Yes\n");
} else {
printf("No\n");
}
return 0;
}
References
Union and Bit Fields, Accessed 2014-04-07, <http://www.rightcorner.com/code/CPP/Basic/union/sample.php>
Access Bits in a Char in C, Accessed 2014-04-07, <https://stackoverflow.com/questions/8584577/access-bits-in-a-char-in-c>
Struct - Bit Field, Accessed 2014-04-07, <http://cboard.cprogramming.com/c-programming/10029-struct-bit-fields.html>
Unless you're working on an embedded platform, I wouldn't be too concerned about the size your net takes up by using an unsigned char to store only a 1 or 0.
To address your specific question: char is the smallest of the C data types. char, signed char, and unsigned char are all only going to take up 1 byte each.
If you want to make your code smaller you can use bitfields to decrees the amount of space you take up, but that will increase the complexity of your code.
For a simple exercise like this, I'd be more concerned about readability than size. One way you can make it more obvious what you're doing is switch to a bool instead of a char.
#include <stdbool.h>
typedef struct {
int rows;
int cols;
bool *vec;
} net_t;
You can then use true and false which, IMO, will make your code much easier to read and understand when all you need is 1 and 0.
It will take up at least as much space as the way you're doing it now, but like I said, consider what's really important in the program you're writing for the platform you're writing it for... it's probably not the size.
The smallest type on C as i know are the char (-128, 127), signed char (-128, 127), unsigned char (0, 255) types, all of them takes a whole byte, so if you are storing multiple bits values on different variables, you can instead use an unsigned char as a group of bits.
unsigned char lives = 128;
At this moment, lives have a 128 decimal value, which it's 10000000 in binary, so now you can use a bitwise operator to get a single value from this variable (like an array of bits)
if((lives >> 7) == 1) {
//This code will run if the 8 bit from right to left (decimal 128) it's true
}
It's a little complex, but finally you'll end up with a bit array, so instead of using multiple variables to store single TRUE / FALSE values, you can use a single unsigned char variable to store 8 TRUE / FALSE values.
Note: As i have some time out of the C/C++ world, i'm not 100% sure that it's "lives >> 7", but it's with the '>' symbol, a little research on it and you'll be ready to go.
You're correct that a char is the smallest type - and it is typically (8) bits, though this is a minimum requirement. And sizeof(char) or (unsigned char) is (1). So, consider using an (unsigned) char to represent (8) columns.
How many char's are required per row? It's (cols / 8), but we have to round up for an integer value:
int byte_cols = (cols + 7) / 8;
or:
int byte_cols = (cols + 7) >> 3;
which you may wish to store with in the net_t data structure. Then:
calloc(n->rows * n->byte_cols, 1) is sufficient for a contiguous bit vector.
Address columns and rows by x and y respectively. Setting (x, y) (relative to 0) :
n->vec[y * byte_cols + (x >> 3)] |= (1 << (x & 0x7));
Clearing:
n->vec[y * byte_cols + (x >> 3)] &= ~(1 << (x & 0x7));
Searching:
if (n->vec[y * byte_cols + (x >> 3)] & (1 << (x & 0x7)))
/* ... (x, y) is set... */
else
/* ... (x, y) is clear... */
These are bit manipulation operations. And it's fundamentally important to learn how (and why) this works. Google the term for more resources. This uses an eighth of the memory of a char per cell, so I certainly wouldn't consider it premature optimization.
I've got 2 chars.
Char 128 and Char 2.
How do I turn these chars into the Short 640 in C?
I've tried
unsigned short getShort(unsigned char* array, int offset)
{
short returnVal;
char* a = slice(array, offset, offset+2);
memcpy(&returnVal, a, 2);
free(a);
return returnVal;
}
But that didn't work, it just displays it as 128. What's the preferred method?
Probably the easiest way to turn two chars, a and b, into a short c, is as follows:
short c = (((short)a) << 8) | b;
To fit this into what you have, the easiest way is probably something like this:
unsigned short getShort(unsigned char* array, int offset)
{
return (short)(((short)array[offset]) << 8) | array[offset + 1];
}
I found that the accepted answer was nearly correct, except i'd run into a bug where sometimes the top byte of the result would be 0xff...
I realized this was because of C sign extension. if the second char is >= 0x80, then converting 0x80 to a short becomes 0xff80. Performing an 'or' of 0xff80 with anything results in the top byte remaining 0xff.
The following solution avoids the issue by zeroing out the top byte of b during its implicit conversion to a short.
short c = (((short)a) << 8) | (0x00ff & b);
I see that there is already an answer, but I'm a bit puzzled about what was going on with your original attempt. The following code shows your way and a technique using a union. Both seem to work just fine. I suppose you might have been running into an endianness problem. Anyway, perhaps this demonstration will be useful even if your problem is already solved.
#include <stdio.h>
#include <string.h>
int main()
{
short returnVal;
char a[2];
union {
char ch[2];
short n;
} char2short;
a[0] = 128;
a[1] = 2;
memcpy(&returnVal, a, 2);
printf("short = %d\n", returnVal);
char2short.ch[0] = 128;
char2short.ch[1] = 2;
printf("short (union) = %d\n", char2short.n);
return 0;
}
Outputs:
short = 640
short (union) = 640
I see that you are not actually trying to shift bits but assemble the equivelant of hex values together, like you would color values in CSS.
Give this code a shot:
char b1=128,b2=2;
char data[16];
sprintf((char *)data,"%x%x",(BYTE)b2,(BYTE)b1);
short result=strtol(data,(char **)NULL, 16);
I want to convert an unsigned int and break it into 2 chars. For example: If the integer is 1, its binary representation would be 0000 0001. I want the 0000 part in one char variable and the 0001 part in another binary variable. How do I achieve this in C?
If you insist that you have a sizeof(int)==2 then:
unsigned int x = (unsigned int)2; //or any other value it happens to be
unsigned char high = (unsigned char)(x>>8);
unsigned char low = x & 0xff;
If you have eight bits total (one byte) and you are breaking it into two 4-bit values:
unsigned char x=2;// or whatever
unsigned char high = (x>>4);
unsigned char low = x & 0xf;
Shift and mask off the part of the number you want. Unsigned ints are probably four bytes, and if you wanted all four bytes, you'd just shift by 16 and 24 for the higher order bytes.
unsigned char low = myuint & 0xff;
unsigned char high = (myuint >> 8) & 0xff;
This is assuming 16 bit ints check with sizeof!! On my platform ints are 32bit so I will use a short in this code example. Mine wins the award for most disgusting in terms of pulling apart the pointer - but it also is the clearest for me to understand.
unsigned short number = 1;
unsigned char a;
a = *((unsigned char*)(&number)); // Grab char from first byte of the pointer to the int
unsigned char b;
b = *((unsigned char*)(&number) + 1); // Offset one byte from the pointer and grab second char
One method that works is as follows:
typedef union
{
unsigned char c[sizeof(int)];
int i;
} intchar__t;
intchar__t x;
x.i = 2;
Now x.c[] (an array) will reference the integer as a series of characters, although you will have byte endian issues. Those can be addressed with appropriate #define values for the platform you are programming on. This is similar to the answer that Justin Meiners provided, but a bit cleaner.
unsigned short s = 0xFFEE;
unsigned char b1 = (s >> 8)&0xFF;
unsigned char b2 = (((s << 8)>> 8) & 0xFF);
Simplest I could think of.
int i = 1 // 2 Byte integer value 0x0001
unsigned char byteLow = (i & 0x00FF);
unsinged char byteHigh = ((i & 0xFF00) >> 8);
value in byteLow is 0x01 and value in byteHigh is 0x00
I have a char array that is really used as a byte array and not for storing text. In the array, there are two specific bytes that represent a numeric value that I need to store into an unsigned int value. The code below explains the setup.
char* bytes = bytes[2];
bytes[0] = 0x0C; // For the sake of this example, I'm
bytes[1] = 0x88; // assigning random values to the char array.
unsigned int val = ???; // This needs to be the actual numeric
// value of the two bytes in the char array.
// In other words, the value should equal 0x0C88;
I can not figure out how to do this. I would assume it would involve some casting and recasting of the pointers, but I can not get this to work. How can I accomplish my end goal?
UPDATE
Thank you Martin B for the quick response, however this doesn't work. Specifically, in my case the two bytes are 0x00 and 0xbc. Obviously what I want is 0x000000bc. But what I'm getting in my unsigned int is 0xffffffbc.
The code that was posted by Martin was my actual, original code and works fine so long as all of the bytes are less than 128 (.i.e. positive signed char values.)
unsigned int val = (unsigned char)bytes[0] << CHAR_BIT | (unsigned char)bytes[1];
This if sizeof(unsigned int) >= 2 * sizeof(unsigned char) (not something guaranteed by the C standard)
Now... The interesting things here is surely the order of operators (in many years still I can remember only +, -, * and /... Shame on me :-), so I always put as many brackets I can). [] is king. Second is the (cast). Third is the << and fourth is the | (if you use the + instead of the |, remember that + is more importan than << so you'll need brakets)
We don't need to upcast to (unsigned integer) the two (unsigned char) because there is the integral promotion that will do it for us for one, and for the other it should be an automatic Arithmetic Conversion.
I'll add that if you want less headaches:
unsigned int val = (unsigned char)bytes[0] << CHAR_BIT;
val |= (unsigned char)bytes[1];
unsigned int val = (unsigned char) bytes[0]<<8 | (unsigned char) bytes[1];
The byte ordering depends on the endianness of your processor. You can do this, which will work on big or little endian machines. (without ntohs it will work on big-endian):
unsigned int val = ntohs(*(uint16_t*)bytes)
unsigned int val = bytes[0] << 8 + bytes[1];
I think this is a better way to go about it than relying on pointer aliasing:
union {unsigned asInt; char asChars[2];} conversion;
conversion.asInt = 0;
conversion.asChars[0] = 0x0C;
conversion.asChars[1] = 0x88;
unsigned val = conversion.asInt;