crc-16 IBM, 0x00 not taken in consideration - arrays

I did test a crc-16/ibm implementation i found on the net. when I test it with hex byte array it works fine but if I include some 0x00 values, then it doesn't give the proper result.
here is its code
unsigned short ComputeCRC16(const unsigned char* buf, unsigned int len) {
unsigned short crc = 0;
for (unsigned int j = 0; j < len; j++)
{
unsigned char b = buf[j];
for (unsigned char i = 0; i < 8; i++)
{
crc = ((b ^ (unsigned char)crc) & 1) ? ((crc >> 1) ^ 0xA001) : (crc >> 1);
b >>= 1;
}
}
return crc;
}
I tested it with this code:
int main() {
//fe b5 5f f7
unsigned char buf1[4096] = { 0xfe, 0xb5, 0x5f, 0xf7 };
//fe b5 00 5f f7 00
unsigned char buf2[4096] = { 0xfe, 0xb5, 0x00, 0x5f, 0xf7, 0x00 };
int a = strlen(buf1);
unsigned short res = ComputeCRC16(buf1, a);
printf("res = %04x\n", res); //res : 7858, the result is correct
int b = strlen(buf2);
unsigned short res = ComputeCRC16(buf2, b);
printf("res = %04x\n", res); //res : d781, the result is not correct
return 0; //the correct result : 26EE
}
to verify the result I use this website:
https://www.lammertbies.nl/comm/info/crc-calculation

Your CRC routine gives correct results. It is your test that's wrong. strlen(p) returns how many bytes there are before the first zero byte at p. For buf2, that's four, not five as you intended. For buf1 it's not even defined, since there can be anything in memory after that array. You might be getting four, if the compiler happened to put zeros after the array.
For testing, you should simply provide len manually. (buf1, 4), (buf2, 5).
By the way, that code could be more efficient. It doesn't have to test with b every time. Just exclusive-oring with b to start has the same effect:
crc ^= buf[j];
for (unsigned char i = 0; i < 8; i++)
crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1;

Related

How to concatenate the hexadecimal data in an array in C

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.

little endian to uint with undetermined numbers of bytes

I was trying to write a function that took in N bytes of little endian hex and made it into an unsigned int.
unsigned int endian_to_uint(char* buf, int num_bytes)
{
if (num_bytes == 0)
return (unsigned int) buf[0];
return (((unsigned int) buf[num_bytes -1]) << num_bytes * 8) | endian_to_uint(buf, num_bytes - 1);
}
however, the value returned is approx ~256 times larger than the expected value. Why is that?
If I needed to do use it for a 4 byte buffer, normally you'd do:
unsigned int endian_to_uint32(char* buf)
{
return (((unsigned int) buf[3]) << 24)
| (((unsigned int) buf[2]) << 16)
| (((unsigned int) buf[1]) << 8)
| (((unsigned int) buf[0]));
}
which should be reproduced by the recursive function I wrote, or is there some arithmetic error that I haven't caught?
The below code snippet would work.
unsigned int endian_to_uint(unsigned char* buf, int num_bytes)
{
if (num_bytes == 0)
return (unsigned int) buf[0];
return (((unsigned int) buf[num_bytes -1]) << (num_bytes -1) * 8) | endian_to_uint(buf, num_bytes - 1);
}
Change 1:
Modified the function argument data type from char* to unsigned char *
Reason: For a given buf[] = {0x12, 0x34, 0xab, 0xcd};
When you are trying to read buf[3] i.e here buf[num_bytes -1] will give you 0xffffffcd instead of just 0xcd because of sign extension. For more info on sign extension refer Sign Extension
Change 2:
Use num_bytes-1 when calculating the shift position value. This was a logical error in calculation of the number of bits to be shifted.
There is absolutely no reason to use recursion here: bit shifts is among the fastest operations available, recursion is among the slowest. In addition, recursion is dangerous, hard to read and gives nasty peak stack consumption. It should be avoided in general.
In addition, your function is not a general one, since you return unsigned int, making the function inferior to the shift version in every single way.
To actually write a generic-size little endian conversion function, you can do like this:
void little_endian (size_t bytes, uint8_t dest[bytes], const uint8_t src[bytes])
{
for(size_t i=0; i<bytes; i++)
{
dest[i] = src[bytes-i-1];
}
}
Working example:
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
void little_endian (size_t bytes, uint8_t dest[bytes], const uint8_t src[bytes])
{
for(size_t i=0; i<bytes; i++)
{
dest[i] = src[bytes-i-1];
}
}
int main (void)
{
uint8_t data [] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
uint32_t u32;
uint64_t u64;
little_endian(4, (uint8_t*)&u32, data);
little_endian(8, (uint8_t*)&u64, data);
printf("%"PRIx32"\n", u32);
printf("%"PRIx64"\n", u64);
return 0;
}

Array of HEX Values to Decimal

I'm reading in HEX values from a file into an array.
The part of the buffer I'm using is contains 4 bytes in Hex -> CE EE 00 00
unsigned int fileLocationOffset = 64;
unsigned char fileSize[4]; //This is actually in a struct.
//Putting here for purposes of this question
unsigned char buff[sizeOfRoot];
fseek(fp, startOfRoot, SEEK_SET); //Seek to point in file fp
fread(buff, 1, sizeOfRoot, fp); //Save contents to a buffer
//Read in 4 Bytes backwards to put as Big-Endian
for(int z = 31; z > 27; z--){
fileSize[31 - z] = buff[fileLocationOffset + z];
}
//TEST: Print Values at each element to see if correct
for(int z = 0; z < 4; z++){
printf("%X ", fileSize[z]);
}
// Output: 0 0 EE CE <- Correct
So, I know that my fileSize array contains the correct values, but now I need to convert 0x00EECE to a decimal.
Could somebody please advise how I should go about doing this?
Ok, so you have the bytes of an int value in big endian order and want to build the value. You could simply place the bytes into an uint32_t variable:
uint32_t bytes_to_int(unsigned char *bytes) {
uint32_t val = 0;
for(int i=0; i<4; i++) {
val <<= 8; //shift 8 positions to the right
val |= *bytes++;
}
return val;
}
With it, the following test program:
int main() {
unsigned char foo[] = { 0, 0, 0xee, 0xce };
unsigned val = bytes_to_int(foo);
printf("%d - 0x%x\n", val, val);
return 0;
}
output as expected:
61134 - 0xeece
What do you do with the data?
Concepts like hex and decimal only apply when you print the data.
What is the output of
printf("%d", *(int *)filesize);
Your previous comment suggests you are on a little endian machine.
The value in your file is also little endian.
Why do you change your endianess?
See following test program:
// big endian
unsigned char fileSize[4] = { 0x0, 0x0, 0xEE, 0xCE };
// little endian
unsigned char fileSize2[4] = { 0xCE, 0xEE, 0x00, 0x00 };
int main(void)
{
int i;
// Output: 0 0 EE CE <- Correct
for (i = 0; i < sizeof fileSize; i++)
printf("%02x ", fileSize[i]);
printf("\n");
for (i = 0; i < sizeof fileSize2; i++)
printf("%02x ", fileSize2[i]);
printf("\n");
printf("%u\n", *(int *)fileSize);
printf("%u\n", *(int *)fileSize2);
}
Output (on pc):
00 00 ee ce
ce ee 00 00
3471704064
61134
You could extract the data as a single unsigned 32-bit integer and use that almost directly (depending on endianness issues of course).
Perhaps something like this:
uint32_t fileSize;
memcpy(&fileSize, buff[fileLocationOffset + 28], 4);
Then for the endianness issue, if you're on Linux you could use be32toh (see e.g. this endian manual page) to convert big-endian to host encoding (and it does nothing if your host system is big-endian):
fileSize = be32toh(fileSize);
The closest function to this in the Windows API is ntohl, which could be used in a similar way.
It's not hard to implement absolute byte-swapping functions, or even macros, for this:
inline uint16_t byteswap16(uint16_t value)
{
return (value & 0xff) << 8 | (value >> 8);
}
inline uint32_t byteswap32(uint32_t value)
{
return byteswap16(value & 0xffff) << 16 | byteswap16(value >> 16);
}
...
fileSize = byteswap32(fileSize);
...
Answer given by Serge Ballesta is correct, however there is one other dirty but short trick to do this.
int main() {
char data[]={0xce,0xee,0,0};
int *ptr;
ptr=data;
printf("%d\n",*ptr);
//if you want to store this result
int x=*ptr;
printf("%d\n",x);
return 0;
}
This way you won't even have to reverse your bytes.
Output:
61134
61134
Here compiler itself takes care of the endianess

Updating every single block (4bits) with different value in 64 bit unsigned variable?

I have a variable unsigned __int64 text=0x0; and I need to and update each 4 bits with different values.
text = b64b63...b3b2b1b0
I have a loop and inside of the loop must be like this :
for(i=0;i<16;i++)
{
b3b2b1b0=a[0]
b7b6b5b4=a[1]
b11b10b9b8=a[2]
..
..
..
}
I tried this one but didn't work
unsigned __int64 temp=0x0;
unsigned __int64 index=0x0;
for(i=0;i<16;i++)
{
index = (text>>(i*4))&0x0F;
temp = a[index];
text = text | temp<<(i*4);
}
thank you so much
You can use bitshifting and bitwise-OR to do this. Assuming the a[n] values are all between 0 and 15 and also unsigned __int64s:
unsigned __int64 text=0x0;
text = a[0] |
a[1] << 4 |
a[2] << 8 |
etc....;
If you don't trust the a[n] values, use (a[n] & 0xF) to clear all but the four least significant bits before shifting. If a[n] is not an unsigned __int64, cast it before shifting.
You could use bit fields:
typedef struct {
int n0 : 4;
int n1 : 4;
int n2 : 4;
int n3 : 4;
int n4 : 4;
int n5 : 4;
int n6 : 4;
int n7 : 4;
int n8 : 4;
int n9 : 4;
int n10 : 4;
int n11 : 4;
int n12 : 4;
int n13 : 4;
int n14 : 4;
int n15 : 4;
} S64;
typedef union {
uint64_t i;
S64 b;
} U64;
Note: you may need to pay attention to to the endianness of your target platform(s), if you require a specific ordering of the 4 bit fields within the 64 bit value.
If you must use a loop, you can do something like
uint64_t text = 0;
for (int i = 15; i >= 0; --i)
{
text <<= 4;
text |= a[i] & 0x0f; // Masking in case a[i] have more than the lowest four bits set
}
Try the below code. I have tried to copy 0x01, 0x02....0x0f into 16 different nibbles. The code extracts the values and shifts them appropriately combined with the OR operation.
#define NIBBLES 16 /* 64-bit has 16 nibbles */
#define MASK 0x0FLLU
int main()
{
unsigned int val[NIBBLES] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
long long unsigned int num = 0, tmp;
int i, shift = 0;
for (i = 0; i < NIBBLES; i++) {
tmp = (val[i] & MASK) << shift;
num = num | tmp;
shift = shift + 4;
}
printf ("0x%llx\n", num);
}
Output: 0xfedcba9876543210

CRC-32 with LFSR Byte by Byte in C

I implemented a CRC32 algorithm in C but after hours of looking around and trying to fix it, it still doesn't work. It compiles but the checksum is not the same as in several online CRC calculators. I suspect the error to be in the line "if (0 != (character & j))" but don't understand it, since it is even mainly the same as the code on wikipedia.
wikipedia
int CRC32_C(char *message){
int length, i, j;
unsigned long p,g;
char character;
p = 0x00000000;
g = 0x04C11DB7;
length = strlen(message);
for (i = 0; i < length; i++){
character=*message;
//iterieren durch die bits jedes zeichens
for (j= 0x80; j != 0; j >>= 1){
//(p & 0x80000000)? 1 : 0)
if (0 != (character & j))
p = (p << 1) ^ g;
else
p <<=1;
}
message++;
}
return p;
}
//sample main
int main(char ** argv, int argc){
char *msg;
int p;
msg = "HALLO";
p = CRC32_C(msg);
printf("p ist 0x%x \n", p);
return 0;
}
Sample input: "HALLO"
Expected result: 0x4E26F361 (according to this page, which uses the same generator polynomial, as seen at the bottom of the page)
Actual result: 0xc25a747d
#chux: I tried removing the "0 !=" in the if clause, but it didn't change the result.
CRC32_C simply stands for "Implemented in C". As the Generator polynomial suggests, it is standard Ethernet.
Thanks for your help
The CRC may be msb to lsb or lsb to msb, and the generator polynomial may be different in the online examples. CRC32_F is msb to lsb, CRC32_R is lsb to msb (with the polynomial reversed). If you can find an online CRC calculator that takes hex, try using hex 01 to test for msb to lsb, or hex 80 to test for lsb to msb. Other variations initialize the crc to 0xffffffff and/or invert (not) the crc after calculating the crc. Looking at a description of ethernet crc, try using CRC32_R, but change the initialization of crc to crc = 0xfffffffful; .
unsigned long CRC32_F(unsigned char *message, size_t length){
size_t i, j;
unsigned long crc,gnp;
crc = 0x00000000ul;
gnp = 0x04C11DB7ul;
for (i = 0; i < length; i++){
crc ^= ((unsigned long)*message)<<24;
for (j = 0; j < 8; j++){
if (crc & 0x80000000ul)
crc = (crc << 1) ^ gnp;
else
crc = (crc << 1);
}
message++;
}
return crc;
}
unsigned long CRC32_R(unsigned char *message, size_t length){
size_t i, j;
unsigned long crc,gnp;
crc = 0x00000000ul;
gnp = 0xEDB88320ul;
for (i = 0; i < length; i++){
crc ^= ((unsigned long)*message)<<0;
for (j = 0; j < 8; j++){
if (crc & 0x00000001ul)
crc = (crc >> 1) ^ gnp;
else
crc = (crc >> 1);
}
message++;
}
return crc;
}
This will generate the CRC 0x4E26F361 from HALLO:
#include <stddef.h>
#include <stdint.h>
/* CRC-32 (Ethernet, ZIP, etc.) polynomial in reversed bit order. */
#define POLY 0xedb88320
/* Compute CRC of buf[0..len-1] with initial CRC of crc. Start
with crc == 0. */
uint32_t crc32c(uint32_t crc, const unsigned char *buf, size_t len)
{
int k;
crc = ~crc;
while (len--) {
crc ^= *buf++;
for (k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
}
return ~crc;
}
The above computes the CRC bit-by-bit, where there are faster approaches. That happens to be CRC in common use, so you can find a fast implementation in zlib, called crc32(), which is already available as an installed library in most systems.

Resources