Let me start by saying that I openly admit this is for a homework assignment, but what I am asking is not related to the purpose of the assignment, just something I don't understand in C. This is just a very small part of a large program.
So my issue is, I have a set of data that consists various data types as follows:
[16 bit number][16 but number][16 bit number][char[234]][128 bit number]
where each block represents a variable from elsewhere in the program.
I need to send that data 8bytes at a time into a function that accepts uint32_t[2] as an input. How do I convert my 234byte char array into uint32_t without losing the char values?
In other words, I need to be able to convert back from the uint32_t version to the original char array later on. I know a char is 1byte, and the value can also be represented as a number in relation to its ascii value, but not sure how to convert between the two since some letters have a 3 digit ascii value and others have 2.
I tried to use sprintf to grab 8byte blocks from the data set, and store that value in a uint32_t[2] variable. It works, but then I lose the original char array because I can't figure out way to go back/undo it.
I know there has to be a relatively simple way to do this, i'm just lacking enough skill in C to make it happen.
Your question is very confusing, but I am guessing you are preparing some data structure for encryption by a function that requires 8 bytes or 2 uint32_t's.
You can convert a char array to uint32_t as follows
#define NELEM 234
char a[NELEM];
uint64_t b[(NELEM+sizeof(uint64_t)-1)/sizeof(uint64_t)]; // this rounds up to nearest modulo 4
memcpy(b,a,NELEM);
for(i .. ) {
encryption_thing(b[i]);
}
or
If you need to change endianess or something, that is more complicated.
#include <stdint.h>
void f(uint32_t a[2]) {}
int main() {
char data[234]; /* GCC can explicitly align with this: __attribute__ ((aligned (8))) */
int i = 0;
int stride = 8;
for (; i < 234 - stride; i += stride) {
f((uint32_t*)&data[i]); }
return 0; }
I need to send that data 8bytes at a time into a function that accepts
uint32_t[2] as an input. How do I convert my 234byte char array into
uint32_t without losing the char values?
you could use a union for this
typedef union
{
unsigned char arr[128]; // use unsigned char
uint32_t uints[16]; // 128/8
} myvaluetype;
myvaluetype value;
memcpy(value.arr, your_array, sizeof(value.arr));
say the prototype that you want to feed 2 uint32_t at a time is something like
foo(uint32_t* p);
you can now send the data 8 bytes at the time by
for (int i = 0; i < 16; i += 2)
{
foo(myvaluetype.uints + i);
}
then use the same struct to convert back.
of course some care must be taken about padding/alignment you also don't mention if it is sent over a network etc so there are other factors to consider.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Is there a way to convert an array of char to array of int32 without iterating every member.
I need to convert a huge amount of data so I'm looking for some faster than:
char ac[1000000];
int32_t ai[1000000];
for(int i=0;i<1000000;i++) {
ai[i]=ac[i];
}
Notes:
I'm not asking about how to convert '3' to 0x03, I'm talking about convert 0x03 (one byte) to 0x00000003 (to 4 bytes)
Not portable is not a problem (platform linux AMD64).
The proposed method is slow.
looking for a library that use SSE instructions or similar.
I need it to feed a math function that works with int32 numbers and my original data is in 8 bits size, so I need to convert it, and obviously I can't cast because is an memory area not a value.
Is there a way to convert an array of char to array of int without iterate every member.
No.
Trying to explain this (I assumed it would be obvious): an int is a different size than a char, so no block copies would ever help you. In one or another way, you have to touch each element.
There might be solutions parallelizing this, e.g. by partitioning the array and using threads to handle the parts. But you would still have to convert each and every element.
Regarding your edit:
convert 0x03 (one byte) to 0x0003 (to bytes)
[...] not portable is not a problem (platform linux AMD64)
There seems to be another misconception: int on Linux x86_64 has four bytes, not two. If you really need two bytes per input value, you should use int16_t.
And yet another remark: Typical SIMD instructions (like in SSE2) won't help you either. They assume the same layout of input and output areas. As already stated, the only "optimization" I can possibly see is parallelizing. There's no way around having to touch each element.
Not sure if this will be faster, you have to check (also it will be depend on the sizeof(int) == 4):
// note: untested
char ac[1000000];
int ai[1000000];
memset(ai, 0, sizeof(int) * 1000000); // this should be very fast
char * d = (char *) (ai + 3); // go to last byte of the first int
for(int i=0;i<1000000;i++) {
d += 4; // go to last byte of the next int
*d=ac[i];
}
Are you sure you need ints?
If not, you could do
char ac[1000000];
uint8_t *ai = (uint8_t*)ac;
if the reason you want them to be ints is because a function takes an int as argument and you need to pass some of the values of the array to it, then there is no problem with this method, as they will be implicitly casted to ints.
I think that converting them to ints just makes you use more memory than you actually need.
EDIT:
If you actually DO need an int array, here is a workaround that does not store more than it needs.
You can make a helper function that just extracts the char value casted to an int from the newly created int array, hence behaving like an int array.
// Endianness test to extract the char number
constexpr bool endianness() {
return *(int*)const_cast<char*>("\x00\x01") & 1;
}
// Get char value casted to int from the int array
int getVal(int *i, int idx) {
int iidx = idx / sizeof(int);
int rem = idx % sizeof(int);
if(endianness()) rem = sizeof(int) - rem - 1;
return (i[iidx] & (0xff << 8*rem)) >> 8*rem;
}
To use this you just convert the char array to an int pointer and just use it, like so.
char ac[1000000];
int *ai = (int*)ac;
cout << getVal(ai, 0);
This will print the value of the first element casted into an int and is actually portable.
I am trying to convert a byte* parameter passed into an mqtt callback function to an int for comparison and I can't seem to get it working. Any help would be welcomed.
int fsrReading;
void callback(char* topic, byte* payload, unsigned int length) {
for (int i=0;i<length;i++) {
Serial.print((char)payload[i]); // This works well
fsrReading = int((char)payload[i]);
if (fsrReading < 0){
...
The correct way to do this depends on exactly what representation of a number is being used.
I suspect the message is a string representation of a number: "1234", which is being received as an array of ascii byte values.
If that is the case, you can rebuild a String object and convert it to an int:
int fsrReading;
void callback(char* topic, byte* payload, unsigned int length) {
String value = "";
for (int i=0;i<length;i++) {
value += (char)payload[i];
}
fsrReading = value.toInt();
...
There is an example of converting a String to an Int in the arduino tutorials here: https://www.arduino.cc/en/Tutorial/StringToIntExample
EDIT: original answer part before explanation:
Depends on compiler, compiler options etc char can be signed or unsigned, cast via (char) can work different than You expect.
Example:
payload[i] is 0x81
unsigned char -> 129, then >0
signed char -> -127, then <0
Your cast via (char) is redundant (and unstable like i said)
I don't give sample code because I don't understand Your goal. Code has contradictions.
Disclaimer: Your byte seems non standard type. I belive that is unsigned char a such type NEVER is <0 .
What is main sense of this variable? In deep, it is signed or unsigned? You can cast (unigned char) but is never<0 or (signed char) - up to You
EDIT:
after comment of asker, and interpretation from knolleary hot to interpret length (important: change of loop sense, maybe you understand author correctly) I give pure C conversion
int val = 0;
for (int i=0; i<length; i++) {
val = val*10 + payload[i]-'0';
}
// If someone know end of number is marked in different way, need implement break of `for`
fsrReading =val;
I believe my is few CPU cycles/RAM better.
EDIT2: I have read few materials from Arduino community, problem with loop concatenation into String is like in many languages: many, many small allocations (while concatenation is totally not required here). Many good Arduino programmers are critical to overuse of String. It isn't "secret knowledge", it is general rule in programming.
http://forum.arduino.cc/index.php?topic=185469.0
http://www.gammon.com.au/concat
I am using Tiva C Series TM4C123GH6PM with Code Composer Studio for getting data from another microcontroller of the same type. Well, I get the data in bytes. The Goal of project is to assemble each 8 bytes and convert them to double then send these double to the computer. I have to use USART to send the data to the computer.
When I use USART, I have two Methods:
One to get data from a USART_x: UARTCharGet(UART1_BASE)
The other to send the data over USART_x: UARTCharPut(UART0_BASE,d)
The problem consists in having two methods that accept only characters. So using these methods for double is impossible since a double is 8 bytes and a character is one byte. I am trying to send doubles to my computer. Any idea?
The second Problem is to write a program from the side of the computer to get the data (bytes) from the microcontroller.
Should I write this program in c (an alternative is using matlab because I will use these data for simulation)?
How can I access com-Port in c (or in matlab if it is possible)?
You need to find a way to break up large amounts of data, and send it to the client, who then needs a way to re-assemble the data, and also know when such data is being sent.
A very simple approach would be to convert all the digits of the double to characters. Inefficient, but it gets the job done easily enough, as shown below. The reason this is preferable is because it lets you easily create your own "instruction set". For example, you could reserve the character '!' as "the letter following ! denotes a special instruction", so when the client sees the sequence "!d", it knows the following 32 bytes of data represent a double, and to re-assemble it.
If you just send the raw bytes, it becomes more convoluted when you want to create escape codes or op codes to signal special circumstances to the client.
Code Listing
#include <stdio.h>
#define BUF_LEN (32)
typedef union {
float f;
struct {
unsigned int mantissa : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
} parts;
} double_cast;
int main(void)
{
double_cast d1;
d1.f = 0.15625;
printf("sign = %x\n",d1.parts.sign);
printf("exponent = %x\n",d1.parts.exponent);
printf("mantissa = %x\n",d1.parts.mantissa);
char buf[BUF_LEN+1] = { 0 };
snprintf(buf, BUF_LEN+1, "%01X%08X%023X", d1.parts.sign, d1.parts.exponent,
d1.parts.mantissa);
// Send over UART
printf("Double as string: [%s]\n", buf);
//UART_printf("!d%s", buf);
return 0;
}
Sample Output
sign = 0
exponent = 7c
mantissa = 200000
Double as string: [00000007C0000000000000000020000]
Credit for the code to break a double into a string goes to u/eran.
Another solution (similar to the solution of Krystian) that works for me. I defined a function that has as parameters a double and an array of Bytes. The double must be converted to an array of Bytes. That´s why I defined an array of Bytes which has a size of 8 Bytes. Here some code:
unsigned char bytesArray[sizeof(double)];
unsigned char * doubleToBytes(double num,unsigned char bytes []){
return memcpy(bytes,&num,sizeof(double));
}
After getting the Bytes in the Array you can send data using the following loop:
for(i=0;i<sizeof(double);i++){
UARTCharPut(UART1_BASE,(unsigned char)*(bytesArray+i));
}
Generally speaking you are facing here serialization problem and the best approach would be using specialized library for this purpose.
In a dirty but simple way you can solve it like that. You have to just properly assemble your data on the other side back to double.
typedef union _MyDouble {
double d;
unsigned char bytes[sizeof(double)];
} MyDouble;
MyDouble my_double;
my_double.d = 1.234;
for(i=0; i < sizeof(double); i++) {
UARTCharPut(UART0_BASE, (char)my_double.bytes[i]).
}
The other thing is that if you are using UART you should encapsulate this union into some frame e.g. in order to successfully reassemble this on the other side.
_____________ ________ __________ ___________ ________
| | | | | |
| FRAME_BEGIN | LENGTH | MyDouble | FRAME_END | CRC-8? |
|_____________|________|__________|___________|________|
The next thing is that you should probably enforce byte alignment on this struct which is done by the compiler directives. It ensures that your struct has no padding bytes etc. and allocates minimum requires size. This is very popular in embedded applications use-cases where some binary object is going to be transmitted on the serial interface - which is exactly your case. Such a simple solution might work on specific hw+sw configuration but for sure it is not portable and good solution from professional point of view.
Here is part of my code , I read some fields of a kernel data structure and compare it with an array. but oddly I see that when I print contents of array orig_poolinfo the first element is 103 though it is actually 128.
int get_poolinfo_fields(vmi_instance_t vmi)
{
int orig_poolinfo[]={128,103,76,51,25,1,32,26,20,14,7,1};
uint64_t poolinfo_table_addr = 0xffffffff81ca4fc0;//kernel 3.11
int poolinfo_table;
int i;
//for( i=0;i<12;i++)
// printf("poolinfo_table=%d %d\n",i,orig_poolinfo[i]);
for( i=0;i<12;i++)
{
vmi_read_64_va(vmi,poolinfo_table_addr, 0, &poolinfo_table);
printf("poolinfo_table=%d orig_poolinfo[%d]=%d\n",poolinfo_table,i,orig_poolinfo[i]);
if(poolinfo_table != orig_poolinfo[i])
printf("hi\n");//return(1);
poolinfo_table_addr = poolinfo_table_addr + 0x4;
}
return(0);
}
and this is the output:
poolinfo_table=128 orig_poolinfo[0]=103
hi
poolinfo_table=103 orig_poolinfo[1]=103
poolinfo_table=76 orig_poolinfo[2]=76
poolinfo_table=51 orig_poolinfo[3]=51
poolinfo_table=25 orig_poolinfo[4]=25
poolinfo_table=1 orig_poolinfo[5]=1
poolinfo_table=32 orig_poolinfo[6]=32
poolinfo_table=26 orig_poolinfo[7]=26
poolinfo_table=20 orig_poolinfo[8]=20
poolinfo_table=14 orig_poolinfo[9]=14
poolinfo_table=7 orig_poolinfo[10]=7
poolinfo_table=1 orig_poolinfo[11]=1
You are mixing two different types int and uint64_t. Their sizes might not be the same.
By using vmi_read_64_va() you copy 8 bytes. If sizeof( int ) is 4 on your system you get undefined behavior. This means anything can happen and your program is not behaving correctly.
Use functions appropriate to your type size and don't mix types.
Can I declare an int array, then initialize it with chars? I'm trying to print out the state of a game after each move, therefore initially the array will be full of chars, then each move an entry will be updated to an int.
I think the answer is yes, this is permitted and will work because an int is 32 bits and a char is 8 bits. I suppose that each of the chars will be offset by 24 bits in memory from each other, since the address of the n+1'th position in the array will be n+32 bits and a char will only make use of the first 8.
It's not a homework question, just something that came up while I was working on homework. Maybe I'm completely wrong and it won't even compile the way I've set everything up?
EDIT: I don't have to represent them in a single array, as per the title of this post. I just couldn't think of an easier way to do it.
You can also make an array of unions, where each element is a union of either char or int. That way you can avoid having to do some type-casting to treat one as the other and you don't need to worry about the sizes of things.
int and char are numeric types and char is guaranteed smaller than int (therefore supplying a char where an int is expected is safe), so in a nutshell yes you can do that.
Yes it would work, because a char is implicitly convertible to an int.
"I think the answer is yes, this is permitted and will work because an int is 32 bits and a char is 8 bits." this is wrong, an int is not always 32 bits. Also, sizeof(char) is 1, but not necessarily 8 bits.
As explained, char is an int compatible type.
From your explanation, you might initially start with an array of int who's values are char, Then as the game progresses, the char values will no longer be relevant, and become int values. Yes?
IMHO the problem is not putting char into an int, that works and is built into the language.
IMHO using a union to allow the same piece of space to be used to store either type, helps but is not important. Unless you are using an amazingly small microcontroller, the saving in space is not likely relevant.
I can understand why you might want to make it easy to write out the board, but I think that is a tiny part of writing a game, and it is best to keep things simple for the rest of the game, rather than focus on the first few lines of code.
Let's think about the program; consider how to print the board.
At the start it could be:
for (int i=0; i<states; ++i) {
printf("%c ", game_state[i]);
}
Then as the game progresses, some of those values will be int.
The issue to consider is "which format is needed to print the value in the 'cell'?".
The %c format prints a single char.
I presume you would like to see the int values printed differently from ordinary printed characters? For example, you want to see the int values as integers, i.e. strings of decimal (or hex) digits? That needs a '%d' format.
On my Mac I did this:
#include <stdio.h>
#define MAX_STATE (90)
int main (int argc, const char * argv[]) {
int game_state[MAX_STATE];
int state;
int states;
for (states=0; states<MAX_STATE; ++states) {
game_state[states] = states+256+32;
}
for (int i=0; i<states; ++i) {
printf("%c ", game_state[i]);
}
return 0;
}
The expression states+256+32 guarantees the output character codes are not ASCII, or even ISO-8859-1 and they are not control codes. They are just integers. The output is:
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? # A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y
I think you'd like the original character to be printed (no data conversion) when the value is the initial character (%c format), but you do want to see data conversion, from a binary number to a string of digit-characters (%d or a relative format). Yes?
So how would the program tell which is which?
You could ensure the int values are not characters (as my program did). Typically, this become a pain, because you are restricted on values, and end up using funny expressions everywhere else just to make that one job easier.
I think it is easier to use a flag which says "the value is still a char" or "the value is an int"
The small saving of space from using a union is rarely worth while, and their are advantages to having the initial state and the current move available.
So I think you end up with something like:
#include <stdio.h>
#define MAX_STATE (90)
int main (int argc, const char * argv[]) {
struct GAME { int cell_state; int move; char start_value } game_state[MAX_STATE];
enum CELL_STATE_ENUM { start_cell, move_cell };
int state;
int states;
for (states=0; (state=getchar())!= EOF && states<MAX_STATE; ++states) {
game_state[states].start_value = state;
game_state[states].cell_state = start_cell;
}
// should be some error checking ...
// ... make some moves ... this is nonsense but shows an idea
for (int i=0; i<states; ++i ) {
if (can_make_move(i)) {
game_state[states].cell_state = move_cell;
game_state[states].move = new_move(i);
}
}
// print the board
for (int i=0; i<states; ++i) {
if (game_state[i].cell_state == start_cell) {
printf("'%c' ", game_state[i].start_value);
} else if (game_state[i].cell_state == move_cell) {
printf("%d ", game_state[i].move);
} else {
fprintf(stderr, "Error, the state of the cell is broken ...\n");
}
}
return 0;
}
The move can be any convenient value, there is nothing to complicate the rest of the program.
Your intent can be made a little more clear my using int8_t or uint8_t from the stdint.h header. This way you say "I'm using a eight bit integer, and I intend for it to be a number."
It's possible and very simple. Here is an example:
int main()
{
// int array initialized with chars
int arr[5] = {'A', 'B', 'C', 'D', 'E'};
int i; // loop counter
for (i = 0; i < 5; i++) {
printf("Element %d id %d/%c\n", i, arr[i], arr[i]);
}
return 0;
}
The output is:
Element 0 is 65/A
Element 1 is 66/B
Element 2 is 67/C
Element 3 is 68/D
Element 4 is 69/E