Say we have 8 bytes saved in an array like:
char array[8];
All of them are set to zero:
for (i = 0; i < 7; i++){
array[i] = 0x00;
}
How can shift a 1 from the first LSBit until the last MSBit like
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x04
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x08
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x10
.....................................
to
0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Here is what I've tried but the result isn't what I'm looking for:
uint8_t buffer[8];
int index = 0 ;
for ( index = 0; index < 8; index++){
buffer[index] = 0x00;
}
*buffer= 0x01;
for( index = 0 ; index < 64; index++){
*buffer = *buffer<< 1 ;
}
UPDATE
Here is an example of what I get:
#include <stdio.h>
int main (){
char buffer[2]={0x01, 0x00};
int i ;
for( i = 0 ; i < 12 ; i++){
printf("0x %2X %x \n",buffer[0], buffer[1]);
*buffer <<= 1;
}
}
And the output is:
0x 1 0
0x 2 0
0x 4 0
0x 8 0
0x 10 0
0x 20 0
0x 40 0
0x FFFFFF80 0
0x 0 0
0x 0 0
0x 0 0
0x 0 0
I really don't understand the 0xFFFFFF80!
What byte that is "LS byte" and which one that is "MS byte" is perhaps not obvious. An array of 8 characters is always allocated in memory like this:
LS address MS address
Byte 0, ... Byte 7
This is true for all CPUs. So the 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 in your question doesn't make any sense: you have misunderstood how arrays are allocated in memory. What you have shown in your examples is how to take bit 0 in the ms byte and left shift it to bit 7 in the ls byte. Which probably doesn't make any sense.
However, if you would attempt to print this array as a 64 bit integer, the value array[0]=1 would give you 0000000000000001 on a little endian machine, but 0100000000000000 on a big endian machine. But nothing in your question states that you want to print the array as a 64 bit value, so it is not clear what you are actually asking.
Try this:
#include <stdio.h>
#include <stdint.h>
typedef union
{
uint8_t array[8];
uint64_t u64;
} my_type;
int main()
{
my_type t = {0};
t.array[0] = 0x01;
// how the array is actually allocated:
for(int i=0; i<8; i++) // 0100000000000000 on all machines
{
printf("%.2X", t.array[i]);
}
printf("\n");
// how the array turns out when printed as a 64 bit int:
printf("%.16llX\n", t.u64); // 0000000000000001 little endian
// perhaps what you intended to do, on a little endian machine
t.u64 <<= 63;
printf("%.16llX\n", t.u64); // 8000000000000000 little endian
return 0;
}
As per harold's comment, just carry the 1. So, to shift one place:
uint8_t carry = 0;
for( index = 7 ; index >= 0; index--){
uint8_t nextCarry = buffer[index] >> 7;
buffer[index] = (buffer[index] << 1) | carry;
carry = nextCarry;
}
EDIT: also, it strikes me that your CPU almost certainly has a native 64-bit type. In which case just use a uint64_t directly rather than an array of bytes and perform variable <<= 1;.
I'm not sure if this is what you want, but the following code does at least what was posed in the question:
uint8_t temp = buffer[0];
printf("Initial Buffer :\n");
for(int i = 0 ; i < 8 ; i++)
printf("0x%X ", buffer[7-i]);
// Left Shift until highest bit that is 1 is found
while(!(temp & 0x80))
temp = temp<<1;
// Re-assignments
buffer[7] = temp;
buffer[0] = 0;
printf("\nFinal Buffer :\n");
for(int i = 0 ; i < 8 ; i++)
printf("0x%X ", buffer[7-i]);
In true sense, this is not "shifting entirely through the buffer", but if you could provide more details on what you wish to accomplish, this code could be modified accordingly.
Since you are trying to treat your char array as a single 64 bit object, why not use an actual 64 bit object?
union
{
char array[8];
uint64_t all;
} data;
int index = 0;
data.all = 0;
data.array[0] = 0x01;
for(index = 0; index < 64; index++)
{
data.all = data.all << 1;
}
Note that this assumes that you are working on a little endian machine.
So I've done it , maybe it's not the best way but it works, and if someone needs I'll be glade to share it :
#include <stdio.h>
#include <stdint.h>
int main (){
uint8_t buffer[8];
char* pChar = buffer;
uint8_t carry =0x01;
int i = 0;
short lock [8];
// Array initialization
for ( i =0 ; i <8; i++){
buffer[i] =0x00;
lock[i] = 0x00;
}
pChar =buffer;
for( i = 0 ; i < 64 ; i++){
*pChar = carry;
printf(" 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x \n",buffer[0], buffer[1],buffer[2],buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]);
carry<<=1;
if( i>=7 && lock[0]==0){
*pChar = 0;
pChar++;
carry=0x01;
lock[0]=1;
}else if ( i>=15 && lock[1]==0) {
*pChar = 0;
pChar++;
carry=0x01;
lock[1]=1;
}else if( i>= 23 && lock[2]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[2] =1;
}
else if( i>= 31 && lock[3]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[3] =1;
}
else if( i>=39 && lock[4]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[4] =1;
}
else if( i>= 47 && lock[5]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[5] =1;
}
else if( i>= 55 && lock[6]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[6] =1;
}
}
thanks for your help !
Related
I want to implement CRC8 generator. CRC8-ATM works without problems. However, when using the polynomial of CRC8-MAXIM, the calculation result is different. Did I calculate the wrong way?
==============================
CRC8-ATM
dat: "AB" = 01000001 01000010
ply: 0x107 = 100000111
res: 0x87
==============================
01000001 01000010 00000000
1000001 11
----------------------------
10000010 00000000
10000011 1
----------------------------
1 1000000
1 00000111
----------------------------
my_res: 10000111 => 0x87 (OK)
==============================
CRC8-MAXIM
dat: "AB" = 01000001 01000010
ply: 0x131 = 100110001
res: 0xA5
==============================
01000001 01000010 00000000
1001100 01
----------------------------
1101 00000010 00000000
1001 10001
----------------------------
100 10001010 00000000
100 110001
----------------------------
1001110 00000000
1001100 01
----------------------------
10 01000000
10 0110001
----------------------------
my_res : 00100010 => 0x22 (Must be 0xA5)
For the calculation results, refer to the site below.
https://crccalc.com
If anyone is familiar with the implementation of CRC8, please help.
Yes, there is.
Regular CRC-8 and CRC-8/MAXIM have different RefIn and RefOut configurations :
RefIn parameter indicates if the data byte should be reversed before being used.
RefOut parameter indicates if the computed CRC should be reversed before appling the final XorOut operation.
Here is a piece of code computing CRC8 algorithms:
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
uint8_t uint8_reverse(uint8_t val)
{
uint8_t ret = 0;
for (size_t i = 0; i < 8; i++)
{
if (val & 0x80)
{
ret |= (1 << i);
}
val <<= 1;
}
return ret;
}
uint8_t crc8(uint8_t const * data, size_t data_size, uint8_t poly, uint8_t init,
bool refin, bool refout, uint8_t xor_out)
{
uint8_t crc = init;
for (size_t i = 0; i < data_size; i++)
{
crc = crc ^ (refin ? uint8_reverse(data[i]) : data[i]);
for (size_t j = 0; j < 8; j++)
{
if (crc & 0x80)
{
crc = (crc << 1) ^ poly;
}
else
{
crc <<= 1;
}
}
}
return (refout ? uint8_reverse(crc) : crc) ^ xor_out;
}
int main(void)
{
printf("--- Check data ---\n");
const uint8_t check[9] = "123456789";
printf("crc8: 0x%02x\n", crc8(check, 9, 0x07, 0x00, 0, 0, 0x00));
printf("crc8-cdma2000: 0x%02x\n", crc8(check, 9, 0x9b, 0xff, 0, 0, 0x00));
printf("crc8-darc: 0x%02x\n", crc8(check, 9, 0x39, 0x00, 1, 1, 0x00));
printf("crc8-itu: 0x%02x\n", crc8(check, 9, 0x07, 0x00, 0, 0, 0x55));
printf("crc8-maxim: 0x%02x\n", crc8(check, 9, 0x31, 0x00, 1, 1, 0x00));
printf("--- 'AB' data ---\n");
const uint8_t ab_data[2] = "AB";
printf("crc8: 0x%02x\n", crc8(ab_data, 2, 0x07, 0x00, 0, 0, 0x00));
printf("crc8-itu: 0x%02x\n", crc8(ab_data, 2, 0x07, 0x00, 0, 0, 0x55));
printf("crc8-maxim: 0x%02x\n", crc8(ab_data, 2, 0x31, 0x00, 1, 1, 0x00));
return 0;
}
It outputs:
--- Check data ---
crc8: 0xf4
crc8-cdma2000: 0xda
crc8-darc: 0x15
crc8-itu: 0xa1
crc8-maxim: 0xa1
--- 'AB' data ---
crc8: 0x87
crc8-itu: 0xd2
crc8-maxim: 0xa5
Note that most of the time RefIn and RefOut have the same value, and code optimization is possible (i.e. avoiding all byte reversing operations).
As noted by #lrntgr, the CRC-8/MAXIM defintion has the input bits and the resulting CRC bits reflected. Re-doing your notation with the input and output reflected:
==============================
CRC8-MAXIM
dat: "AB" reflected = 10000010 01000010
ply: 0x131 = 100110001
res: 0xA5
==============================
10000010 01000010 00000000
10011000 1
----------------------------
11010 11000010 00000000
10011 0001
----------------------------
1001 11010010 00000000
1001 10001
----------------------------
1011010 00000000
1001100 01
----------------------------
10110 01000000
10011 0001
----------------------------
101 01010000
100 110001
----------------------------
1 10010100
1 00110001
----------------------------
my_res : 10100101 => reflected 10100101 = 0xA5
For this particular example, 0xA5 reflected is 0xA5! So, unfortunately, you cannot see that the final reflection of the CRC is needed. But, it is. Do another example to see that.
Also as noted, the actual calculation does not need to reflect the input and output bits, but instead can have the exact same effect by instead reflecting the polynomial and shifting down instead of up. The code then is:
unsigned crc8maxim(unsigned char const *dat, size_t len) {
unsigned crc = 0;
for (size_t i = 0; i < len; i++) {
crc ^= dat[i];
for (unsigned k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ 0x8c : crc >> 1;
}
return crc;
}
where the 0x8c is the reflection of 0x31, the polynomial bits excluding x8.
I have my data field as follows DATA = 0x02 0x01 0x02 0x03 0x04 0x05 0x06 0x07 Now I want to concatenate this data as follows DATA = 0x01020304050607. How can I do it using C program. I found a program in C for concatenation of data in an array and the program is as follows:
#include<stdio.h>
int main(void)
{
int num[3]={1, 2, 3}, n1, n2, new_num;
n1 = num[0] * 100;
n2 = num[1] * 10;
new_num = n1 + n2 + num[2];
printf("%d \n", new_num);
return 0;
}
For the hexadecimal data in the array how can I manipulate the above program to concatenate the hexadecimal data?
You need a 64 bit variable num as result, instead of 10 as factor you need 16, and instead of 100 as factor, you need 256.
But if your data is provided as an array of bytes, then you can simply insert complete bytes, i.e. repeatedly shifting by 8 bits (meaning a factor of 256):
int main(void)
{
uint8_t data[8] = { 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
unsigned long long num = 0;
for (int i=0; i<8; i++) {
num <<=8; // shift by a complete byte, equal to num *= 256
num |= data[i]; // write the respective byte
}
printf("num is %016llx\n",num);
return 0;
}
Output:
num is 0201020304050607
Lest say you have input like
int DATA[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
If you want output like 0x0001020304050607, to store this resultant output you need one variable of unsigned long long type. For e.g
int main(void) {
int DATA[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
int ele = sizeof(DATA)/sizeof(DATA[0]);
unsigned long long mask = 0x00;
for(int row = 0; row < ele; row++) {
mask = mask << 8;/* every time left shifted by 8(0x01-> 0000 0001) times */
mask = DATA[row] | mask; /* put at correct location */
}
printf("%016llx\n",mask);
return 0;
}
Here's some kind of hack that writes your data directly into an integer, without any bitwise operators:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
uint64_t numberize(const uint8_t from[8]) {
uint64_t r = 0;
uint8_t *p = &r;
#if '01' == 0x4849 // big endian
memcpy(p, from, 8);
#else // little endian
for (int i=7; i >= 0; --i)
*p++ = from[i];
#endif
return r;
}
int main() {
const uint8_t data[8] = { 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
printf("result is %016llx\n", numberize(data));
return 0;
}
This does work and outputs this independently of the endianness of your machine:
result is 0201020304050607
The compile-time endianness test was taken from this SO answer.
I have my following program that has a function that will extract the particular Bytes from a frame of 8 Bytes data and will give a corresponding value needed based on the start bit and bit length (length counted from the start bit).
How can i pass the data of 8 bytes which is in hexa decimal to my pointer *data in the main function.
For example this is my frame data in hexadecimal '05 00 00 00 00 03 E8 00'. Here is my program. Would be grat if someone help me to solve this. Should i take an array and pass the data as 0x05 0x00 0x00 0x00 0x00 0x03 0xE8 0x00 into the array and then give assign address of the array to the pointer variable? or just take a variable that holds 0x050000000003E800 and assign this address to the pointer.Are the both same? Thanks in advance.
union u_t
{
uint16_t u16;
uint8_t u8[2];
};
uint16_t Frame2Data(uint8_t *data,uint8_t startBit,uint16_t length)
{
uint16_t mask;
uint8_t start;
uint8_t firstByte,offset;
uint8_t numShift;
union u_t ut;
/*if(length == 8) //preliminary, has to be fixed by correct function.
mask = 0xff;*/
if(length == 7)
mask = 0x7F;
if(length == 10)
mask = 0x3ff;
if(length == 12)
mask = 0xfff;
firstByte = startBit / 8;
offset = (firstByte+2) * 8;
start = startBit + length;
numShift = offset - start;
ut.u8[1] = data[firstByte];
ut.u8[0] = data[firstByte+1];
return (ut.u16 >> numShift) & mask;
}
int main()
{
??????????
uint8_t sB = 46;
uint16_t l = 7;
uint16_t extractValue = Frame2Data(?,sB,l);
return 0;
}
To pass data written in hexadecimal to data, you can simply write:
uint8_t data [] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE8, 0x00};
Note that variable mask is uninitialized, because l is equal to 7 and all instructions to initialize variable mask are dead code, as show in red, with a source code analyzer:
https://taas.trust-in-soft.com/tsnippet/t/6d486c5b
final and last update (I promise)
The core of the problem is traversing the data, as Jonathan Leffler kind of alluded. The binary data is "arranged" in a matrix. For example, if I have 3 events and 4 parameters of bitwidth 8, the binary data
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
would look like
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
I have two for loops i & j, and I need to calculate the offset using that.
I initially had
(i * PAR * 2) + (j * PnB/8)
Where PAR is the number of Parameters, PnB is the bitwidth, and i is from 0 to total events and j is from 0 to PAR. This is incorrect, and not sure how I got this formula.
==
I am working on an in-house flow analysis software and am running into some issues. The FCS sample data file I am using to test the software was generated with FACSCaliber on MacOS 9 CellQuest. When I extract the data points for FSC-H and SSC-H I don't get the same results as I would on other flow software (namely FlowJo). I understand that data generated on MacOS 9 CellQuest is stored in big endian order and believe that I am correctly transforming the data as such:
for (int i = 0; i < params[j-1].PnB/8; ++i)
{
lebyte[i] = (bytes[(params[j-1].PnB/8)-1-i] & 0xff) << i*8u;
cx |= lebyte[i];
}
The code may not be elegant but it seems to do what I intend it to do with known data samples.
PnB is the bitwidth
PnR is the channel value range
The result I get when using real flow data looks correct in that the values are within the range specified by PnR, i.e. if PnR = 1024 the data stored in the 16bit space is between 0 - 1023.
However, when I plot the data I get a skewed dot plot where the scatters bend towards the FSC-H x axis.
Here is an excerpt from the FCS 3.1 Standard (Data File Standard for Flow Cytometry, International Society for Advancement of Cytometry; P. 13):
$BYTEORD/n1,n2,n3,n4/ $BYTEORD/4,3,2,1/ [REQUIRED]
This keyword specifies the endianness of the data, i.e., the byte order used to binary store numeric data values in the data set. This value of the keyword corresponds to the order from numerically least significant {1} to numerically most significant {4} in which four binary data bytes are written to compose a 32-bit word in the data acquisition computer. The numbers are separated by commas (ASCII 44). Only two distinct values are allowed:
$BYTEORD/1,2,3,4/ (little endian, i.e., least significant byte written first, e.g., x86 based personal computers)
$BYTEORD/4,3,2,1/ (big endian, i.e., least significant byte is written last, e.g., PowerPC including older Apple Macintosh computers prior to switch to Intel-based architecture)
One of these values shall be used to specify the endianness even if the size of data values exceeds 32 bits ($DATATYPE/D/)
I apologize in advance if I did not do a good job explaining and would be happy to further clarify any points as necessary. Any help will be very much appreciated.
Update
Attached image to illustrate point.
Figure 1
Update 2
I made a simplified version of the endian converter and tested it.
#include <stdio.h>
#include <stdlib.h>
int main() {
int PnB = 16; // bitwidth of data stored for a specific channel value
// for example the data value for sample A is stored in 16 bits.
char bytes[PnB/8];
unsigned int lebyte[PnB/8];
unsigned int cx = 0;
unsigned int b0, b1;
/* | [0] | [1] |
* | 0xff | 0x03 |
*/
bytes[1] = 0x03;
bytes[0] = 0xff;
// in big endian print out
b0 = (bytes[0] & 0xff) << 8u;
b1 = bytes[1] & 0xff;
cx = b0 | b1;
printf("%d\n", cx);
cx = 0;
// convert to little endian
for (int i = 0; i < PnB/8; ++i)
{
lebyte[i] = (bytes[i] & 0xff) << i*8u;
cx |= lebyte[i];
}
printf("%d\n", cx);
}
The results were correct:
65283
1023
So I made the corrections to the original source code (changes made in original post to conserve space).
Additionally I am doing memcpy to copy data over from a buffer.
memset(bytes, '\0', sizeof(char)*params[j-1].PnB/8);
memcpy(bytes, databuf+((i*data->PAR*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);
But I still get a skewed data. It may be something to do with how the data is transformed. I just can't find any information online and I'm sure the makers of FlowJo would be unwilling to share the secret ;). I'll keep looking and see what I find.
Update 3
sorry to make it longer but additional information:
typedef struct _fcs_parameter {
double f1; // logarithmic decade
double f2; // minimum value on log scale
unsigned int PnB; // bitwidth
unsigned int PnR; // range
fcs_events *events; // event data
char *sname; // short name
char *lname; // filter name
} fcs_parameter;
Take a good hard look at the memset() and memcpy() lines you show. Since you've not shown how i is set, nor what's in your params array of structures, it's a bit hard to interpret. However, if you have any varying sizes in the PnB member, then I think your memcpy() offset calculation is bogus.
Here's some code and the output from it; you'll have to adapt it a bit to your scenario. The last section tries to emulate your memset/memcpy code, given that there's no explanation of a number of the variables you show. It includes an alternative interpretation that seems to make more sense.
You could make some of the functions into static inline, assuming you have C99. There are other bits of code that also assume C99. It's not hard to fix it to C89, but I'm not going to do that for you.
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static uint16_t convert_uint16be(uint8_t const *bytes)
{
uint16_t r = (bytes[0] << 8) | bytes[1];
return r;
}
static uint32_t convert_uint32be(uint8_t const *bytes)
{
uint32_t r = (((((bytes[0] << 8) | bytes[1]) << 8) | bytes[2]) << 8) | bytes[3];
return r;
}
static void print16(uint8_t const *bytes)
{
uint16_t r1 = convert_uint16be(bytes);
int16_t r2 = convert_uint16be(bytes);
printf("0x%.2X 0x%.2X = 0x%.4" PRIX16 " = %6" PRId16 "\n", bytes[0], bytes[1], r1, r2);
}
static void print32(uint8_t const *bytes)
{
uint32_t r1 = convert_uint32be(bytes);
int32_t r2 = convert_uint32be(bytes);
printf("0x%.2X 0x%.2X 0x%.2X 0x%.2X = 0x%.8" PRIX32 " = %11" PRId32 "\n", bytes[0], bytes[1], bytes[2], bytes[3], r1, r2);
}
int main(void)
{
int PnB = 16; // bitwidth of data stored for a specific channel value
// for example the data value for sample A is stored in 16 bits.
char bytes[PnB/8];
unsigned int lebyte[PnB/8];
unsigned int cx = 0;
unsigned int b0, b1;
/* | [0] | [1] |
* | 0xff | 0x03 |
*/
bytes[0] = 0xff;
bytes[1] = 0x03;
// in big endian print out
b0 = (bytes[0] & 0xff) << 8u;
b1 = bytes[1] & 0xff;
cx = b0 | b1;
printf("%5d = 0x%.4X\n", cx, cx);
// convert to little endian
cx = 0;
for (int i = 0; i < PnB/8; ++i)
{
lebyte[i] = (bytes[i] & 0xff) << i*8u;
cx |= lebyte[i];
}
printf("%5d = 0x%.4X\n", cx, cx);
print16((uint8_t *)bytes);
uint8_t data[] =
{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xFF,
0x00, 0x00, 0xFF, 0xFF,
0x08, 0x08, 0x09, 0xC0,
0x80, 0x80, 0x90, 0x0C,
0xFF, 0xFF, 0xED, 0xBC,
};
int data_size = sizeof(data) / sizeof(data[0]);
for (int i = 0; i < data_size; i += 2)
print16(&data[i]);
for (int i = 0; i < data_size; i += 4)
print32(&data[i]);
{
struct { int PnB; } params[] = { { 16 }, { 16 }, { 32 }, { 16 }, { 16 }, };
int num_params = sizeof(params) / sizeof(params[0]);
uint8_t value[4];
int i = 0;
int num = num_params;
int offset = 0;
for (int j = 1; j <= num; j++)
{
memset(value, '\0', sizeof(char)*params[j-1].PnB/8);
printf("i = %2d; j = %2d; offset = %2d; calc = %2d; size = %2d\n",
i, j, offset, ((i*7*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);
/* The calculation works plausibly when all params[n].PnB are the same
* size, but not otherwise
*/
memcpy(value, data+((i*7*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);
if (params[j].PnB == 16)
print16(value);
else
print32(value);
memcpy(value, data+offset, params[j-1].PnB/8);
if (params[j].PnB == 16)
print16(value);
else
print32(value);
offset += params[j-1].PnB/8;
}
}
return 0;
}
Sample output:
65283 = 0xFF03
1023 = 0x03FF
0xFF 0x03 = 0xFF03 = -253
0x00 0x00 = 0x0000 = 0
0x00 0x00 = 0x0000 = 0
0x00 0x00 = 0x0000 = 0
0x03 0xFF = 0x03FF = 1023
0x00 0x00 = 0x0000 = 0
0xFF 0xFF = 0xFFFF = -1
0x08 0x08 = 0x0808 = 2056
0x09 0xC0 = 0x09C0 = 2496
0x80 0x80 = 0x8080 = -32640
0x90 0x0C = 0x900C = -28660
0xFF 0xFF = 0xFFFF = -1
0xED 0xBC = 0xEDBC = -4676
0x00 0x00 0x00 0x00 = 0x00000000 = 0
0x00 0x00 0x03 0xFF = 0x000003FF = 1023
0x00 0x00 0xFF 0xFF = 0x0000FFFF = 65535
0x08 0x08 0x09 0xC0 = 0x080809C0 = 134744512
0x80 0x80 0x90 0x0C = 0x8080900C = -2139058164
0xFF 0xFF 0xED 0xBC = 0xFFFFEDBC = -4676
i = 0; j = 1; offset = 0; calc = 2; size = 2
0x00 0x00 = 0x0000 = 0
0x00 0x00 = 0x0000 = 0
i = 0; j = 2; offset = 2; calc = 4; size = 2
0x00 0x00 0x00 0x00 = 0x00000000 = 0
0x00 0x00 0x00 0x00 = 0x00000000 = 0
i = 0; j = 3; offset = 4; calc = 12; size = 4
0x08 0x08 = 0x0808 = 2056
0x00 0x00 = 0x0000 = 0
i = 0; j = 4; offset = 8; calc = 8; size = 2
0x00 0x00 = 0x0000 = 0
0x00 0x00 = 0x0000 = 0
i = 0; j = 5; offset = 10; calc = 10; size = 2
0xFF 0xFF 0x03 0xFF = 0xFFFF03FF = -64513
0xFF 0xFF 0x03 0xFF = 0xFFFF03FF = -64513
The problem was the formula I was using to calculate the offset.
I should have used the following:
for (int i = 0; i < data->TOT; ++i)
{
for (int j = 0; j < data->PAR; ++j)
{
// code removed for brevity
memset(bytes, '\0', sizeof(char)*params[j].PnB/8);
memcpy(bytes, databuf+((i*data->PAR*params[j].PnB/8)+(j*params[j].PnB/8)), params[j].PnB/8);
// more code here
}
}
Thanks for all your help! I wouldn't not have realized that the problem was the way I was calculating the offset if you had not mentioned the PnB problem.
This question already has answers here:
Printing hexadecimal characters in C
(7 answers)
Closed 9 years ago.
Following is a code to see how different data types are stored in memory.
#include <stdio.h>
void newline(void)
{
putchar('\n');
}
void showbyte(char *string, int len)
{
int i;
for (i = 0; i < len; i++)
printf("%p\t0x%.2x\n", string+i, *(string+i));
}
int main()
{
int i = 12345;
float f = 1234.5;
double d = 1234.5;
char name[] = "12345";
showbyte((char *)&i, sizeof i);
newline();
showbyte((char *)&f, sizeof f);
newline();
showbyte((char *)&d, sizeof d);
newline();
showbyte((char *)&name, sizeof name);
return 0;
}
Output
0x7fff8a9ab2cc 0x39
0x7fff8a9ab2cd 0x30
0x7fff8a9ab2ce 0x00
0x7fff8a9ab2cf 0x00
0x7fff8a9ab2c8 0x00
0x7fff8a9ab2c9 0x50
0x7fff8a9ab2ca 0xffffff9a
0x7fff8a9ab2cb 0x44
0x7fff8a9ab2c0 0x00
0x7fff8a9ab2c1 0x00
0x7fff8a9ab2c2 0x00
0x7fff8a9ab2c3 0x00
0x7fff8a9ab2c4 0x00
0x7fff8a9ab2c5 0x4a
0x7fff8a9ab2c6 0xffffff93
0x7fff8a9ab2c7 0x40
0x7fff8a9ab2b0 0x31
0x7fff8a9ab2b1 0x32
0x7fff8a9ab2b2 0x33
0x7fff8a9ab2b3 0x34
0x7fff8a9ab2b4 0x35
0x7fff8a9ab2b5 0x00
The IEEE-754 representation for float 1234.5 is 0x449a5000, and for double 1234.5 is 0x40934A0000000000. When it printed the float and double variable contents, it shows a 4-byte content. ie,
0x7fff8a9ab2ca 0xffffff9a and
0x7fff8a9ab2c6 0xffffff93. But each memory location can store only 1-byte of data, then why does it happen?
unsigned is your friend in this case, because char is by default a signed type
if you change some of the types from char to unsigned char you get the correct result:
#include <stdio.h>
void newline(void)
{
putchar('\n');
}
void showbyte(unsigned char *string, int len)
{
int i;
for (i = 0; i < len; i++)
printf("%p\t0x%.2x\n", string+i, *(string+i));
}
int main()
{
int i = 12345;
float f = 1234.5;
double d = 1234.5;
char name[] = "12345";
showbyte((unsigned char *)&i, sizeof i);
newline();
showbyte((unsigned char *)&f, sizeof f);
newline();
showbyte((unsigned char *)&d, sizeof d);
newline();
showbyte((unsigned char *)&name, sizeof name);
return 0;
}
In this case you get:
0x7fff5d5a98b8 0x39
0x7fff5d5a98b9 0x30
0x7fff5d5a98ba 0x00
0x7fff5d5a98bb 0x00
0x7fff5d5a98b4 0x00
0x7fff5d5a98b5 0x50
0x7fff5d5a98b6 0x9a
0x7fff5d5a98b7 0x44
0x7fff5d5a98a8 0x00
0x7fff5d5a98a9 0x00
0x7fff5d5a98aa 0x00
0x7fff5d5a98ab 0x00
0x7fff5d5a98ac 0x00
0x7fff5d5a98ad 0x4a
0x7fff5d5a98ae 0x93
0x7fff5d5a98af 0x40
0x7fff5d5a98a2 0x31
0x7fff5d5a98a3 0x32
0x7fff5d5a98a4 0x33
0x7fff5d5a98a5 0x34
0x7fff5d5a98a6 0x35
0x7fff5d5a98a7 0x00