binary to int with strtol in C [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm extracting 8 bytes from a big-endian binary file to decode into actual readable information, the second nibble from byte 4, byte 5 and byte 6 need to be concatenated and printed as a long integer value:
example input data (in binary): 0000 0000 0101 0110 1111 1000 0101 0101 0000 0001 0011 1010 0101 0000 0000 0110
example input data (hex representation): 0x0056f855013a5006
In bold are the bits i'm intending to print as long integer.
expected output: 80464
I tried the following but the result of strtol is always 0, I tried using base 0,2,10,16 always result 0.
#include<stdio.h>
#include<stdlib.h>
int main()
{
unsigned char fromfile[8]; //contains 8 bytes from a binary file
unsigned long int output; //output to be printed
unsigned char numbers[4];
numbers[0] = fromfile[4]&0x0f;
numbers[1] = fromfile[5];
numbers[2] = fromfile[6];
numbers[3] = '\0';
output=strtol (numbers,NULL,2);
printf("%lu",output);
return 0;
}
To elaborate fromfile array contains the following:
fromfile[0]=0x00;
fromfile[1]=0x56;
fromfile[2]=0xf8;
fromfile[3]=0x55;
fromfile[4]=0x01;
fromfile[5]=0x3a;
fromfile[6]=0x50;
fromfile[7]=0x06;
Compiling this code using the gcc compiler on a centos virtual machine.

Assuming the input byte order is big-endian, you can do this:
unsigned char fromfile[8]; //contains 8 bytes from a binary file
unsigned long int output; //output to be printed
output =
(fromfile[4] & 0xf) << 16 |
fromfile[5] << 8 |
fromfile[6];
printf("%lu", output);
To explain what's happening in the expression assigned to output, let's look at bytes 4 through 6 of the input which correspond to the binary digits 23 through 0 of the desired value (because of the big endian byte order):
byte: 4 5 6
bit: 23 15 7 0
00001111 11111111 11111111
We're interested in the bits masked with 1 and not interested in bits masked with 0.
fromfile[4] & 0xf takes byte 4 and masks its value with F16 = 000011112, which is exactly the mask underneath byte 4 in the figure above, using the bitwise AND operation (&).
... << 16 shifts the result of step 1 to the left by 16 binary digit positions, which is exactly the position where we need the lower nibble of byte 4 to go according to the figure above.
fromfile[5] << 8 – similarly to step 2, this takes byte 5 and shifts it to the left by 5 positions because that's where its bits are supposed to go.
fromfile[6] doesn't perform a bit shift, because the value read from byte 6 needs to be mapped to the lowest 8 bits of the output value anyway.
So now we have three values (X, Y, and Z mark unknown bits of the values x, y, and z respectively):
0000XXXX 00000000 00000000
00000000 YYYYYYYY 00000000
00000000 00000000 ZZZZZZZZ
To assemble them into one value, we use the binary OR operation (|) twice (x | y | z):
0000XXXX YYYYYYYY ZZZZZZZZ
This is exactly how we want the bits of the input data arranged and we're done.

Related

Analysing program bitshifting

I'll start with the code rightaway:
#include <stdio.h>
int main()
{
unsigned char value = 0xAF;
printf("%02x\n", value);
value = (value << 4) | (value >> 4);
printf("%02x\n", value);
return 0;
}
Firstly I thought you can't store numbers in chars and that you would need to make that an int. Appearently not. Then, if I did the bitshifting mats:
value << 4 = 101011110
value >> 4 = 1010111
101011110
| 1010111
=101011111
and that would be 0x15f.
If I compile that code it prints
af
fa
Can anyone explain to me where I'm thinking wrong?
Bit shifting 4 shifts 4 binary digits, not 2 as you seem to be showing. It also shifts 1 hex digit. So if you have 0xAF, shifting left 4 gives you 0xF0. Because it is a char, it only has 8 bits and the A is cut off. Shifting right 4 similarly yields 0xA. 0x0A | 0xF0 == 0xFA.
Start with the baseline, 0xaf is 1010-111116 (and we're assuming an eight-bit char here based on the code though it's not mandated by the standard).
The expression value << 4 will left-shift that by four bits (not one as you seem to think), giving 1010-1111-000016 and, yes, it's more than an eight-bit char because of integer promotions (both operands of a << expression are promoted to int as per ISO C11 6.5.7 and also in earlier iterations of the standard).
The expression value >> 4 will right-shift it by four bits, giving 101016.
When you bitwise-or those together, you get:
1010-1111-0000
1010
==============
1010-1111-1010
and when you finally try to shoe-horn that back into the eight-bit value, it lops off the upper bits, giving 1111-101016, which is 0xFA.
You might have messed up the bit representations in your calculation.
Ok. I will try to explain according to the code you have provided.
value 0XAF = 10101111
value << 4 = 11110000
value >> 4 = 00001010
11110000
|00001010 = 11111010 and hence the 0XFA.
Explanation:
1. Representation is in binary 8 bit.
2. When you left/right shift by a number, I think you are considering it in terms of multiplication and division, but in 8-bit binary representation it just gets shifted by 4 places and the bits get replaced by 0.
Hope this helps.
because sizeof(unsigned char) is equal to 1.its a 8bit data.
the range of "value" is from 0x0 to 0xFF, that's the valid bit is from bit0 to bit7.
so when assign 0x15F to "value" after bitshifting, only the data from bit 0 to bit7 are assigned to variable "value", bit8 is cut off.
0x15f ---binarization---> 0001 0101 1111
variable "value" is a 8bit data, so, only 0101 1111 is assigned to it.
value ---binarization---> 0101 1111

When making binary masks for working and isolating bits and bytes, what's the fastest way to convert from Binary to Hex?

Assume I have the following binary string:
110110010110
From which I need only the 4th 5th and 6th bits, we've learned to use a mask like this
000000111000
So with the binary & operation I will get the bits I wanted and all I have left to do is shift them to the right.
Since C does not work with plain binary numbers we were told it's easiest to convert the binary mask string to a hexadecimal number. My lecturer used a super quick method to convert a binary string to a hexadecimal number.
What is the easiest and correct way to create those masks?
Each set of four bits corresponds to one hex 'digit'. Learn those, then just start converting blocks of four from right to left. (If you're converting a bit string that's not a multiple of four bits, then just add zeros to the left end until it is for the last conversion.)
0000 : 0x0
0001 : 0x1
0010 : 0x2
0011 : 0x3
0100 : 0x4
0101 : 0x5
0110 : 0x6
0111 : 0x7
1000 : 0x8
1001 : 0x9
1010 : 0xA
1011 : 0xB
1100 : 0xC
1101 : 0xD
1110 : 0xE
1111 : 0xF
For string to string? Grab 4 bits, find the number (0-15) then use as index for a table lookup. For a mask:
hex_digit = val & 0x0F;
Shift down 4 bits with:
val = val >> 4;
In my opinion, it would be helpful to cut your big string into smaller pieces of four bits, starting from the end (least significant bit). For example, your binary number 110110010110 could be written as 1101 1001 0110. If you have a number that can't be properly cut into pieces of four bits, say 1000011010, you should write it as 10 0001 1010.
Now, it's much more simple. In hexadecimal notation, 0 is 0 and f is 15. You start counting from zero, but instead of using 10 symbols, you now use 16. So it goes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f.
You can replace each group of bits with its hexadecimal symbol! In your example (i.e. 1101 1001 0110) it would be d96, while in my example (i.e. 10 0001 1010) it would be 21a. For every one you find in a binary string, you add 2 ^ (position - 1) to your result, where position = 1 for the least significant bit. For example in 0110 you have 1 in position 2 (i.e. 2 ^ (2 - 1) = 2 ^ 1 = 2) and in position 3 (i.e. 2 ^ (3 - 1) = 2 ^ 2 = 4), so it is 2 + 4 = 6. Now, simply prepend 0x to tell the compiler that what follows is a Hexadecimal number and it becomes 0xd96.
In any case, writing a number as it is means it is in decimal notation, prepending a 0 suggests it is octal and prepending a 0x suggests it is a hexadecimal.
I hope this helps! :D

C: bit operations on a variable-length bit string

I'm doing some bit operations on a variable-length bit string.
I defined a function setBits(char *res, int x, int y) that should work on that bit string passed by the *res variable, given a x and y (just to mention, I'm trying to implement something like a Bloom filter using 8 bits per x):
void setBits(char *res, int x, int y)
{
*res |= x << (y * 8)
}
E.g. given the following x-y-vectors {0,0} ; {0,1} ; {1,2} ; {2,3}, I expect a bit string like this (or vice-versa depending whether little- or big-endian, but that isn't important right now):
0000 0010 0000 0001 0000 0000 0000 0000
So the lowest 8 bits should come from {0,0}, the second 8 bits from {0,1}, the next 8 bits come from {1,2} and the last from {2,3}.
Unfortunately, and I don't seem to get the reason for that, setBits always returns only the last result (in this case i.e. the bit string from {2,3}). I debugged the code and realized that *res is always 0 - but why? What am I doing wrong? Is it that I chose char* that it doesn't work or am I completely missing something very stupid?
Assuming 8-bit chars, the maximum value you can store in *res is 0xff i.e. (1<<8)-1.
Consider what happens when you call setBits for x=1, y=1
x << (y * 8) == 1 << (1 * 8)
== 1 << 8
== 0x100
*res is an 8-bit value so can only store the bottom 8 bits of this calculation. For any non-zero value of y, the bits which can be stored in *res are guaranteed to be 0.

how to keep only the lowest 8 bits [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do i get the lower 8 bits of int?
I will create checksum calculator. I do not understand how I can do "Now take the result of 0x247 and keep only the lowest 8 bits which in this example is 0x47" in c. Can you help me ?
Easy, use a bitmask!
You can do this by using the bitwise AND operator.
Here is some code:
#include <stdio.h>
int main(){
int number = 0x247, firsteight;
firsteight = number & 0xFF;
printf("%x, %x", number, firsteight);
return 0;
}
It works because 0xFF equals 11111111 in binary.
So this is what happens:
1001000111 = 0x247
0011111111 = 0xFF
----------- & (bitwise AND)
0001000111
This is an obvious duplicate, but this comment but this is hex value. 0x247 bothered me. There's lots of ways to represent the same number in a system:
int val = 01107; // 583 in octal
int val2 = 0x247; // 583 in hex
int val3 = 583; // 583 in dec
but they're all the same value, if I wanted to get the lower 8 bits of any of them you do it the same way, mask the number with a bitwise operator.
val3 & 255 = lower 8 bits
val2 & 0xFF = lower 8 bits
val & 0377 = lower 8 bits
Don't think I mean you have to use hex against hex either:
(val & 255) == (val2 & 255)
is a true statement. That's why, regardless of how the numbers are represented it's usually eaiset to think of it in binary:
0010 0100 0111
& 0000 1111 1111
----------------
0000 0100 0111 <-- only the last 8 bits are kept
If you want only last 8 bits from a int value, do & with 0xFF.
int a = 0x247;
int b = 0;
b = a & 0xFF;
Use bitwise operators. For example:
0101010011010001 & 0000000011111111
equals to 11010001.

C bitwise shift

I suppose sizeof(char) is one byte. Then when I write following code,
#include<stdio.h>
int main(void)
{
char x = 10;
printf("%d", x<<5);
}
The output is 320
My question is, if char is one byte long and value is 10, it should be:
0000 1010
When I shift by 5, shouldn't it become:
0100 0001
so why is output 320 and not 65?
I am using gcc on Linux and checked that sizeof(char) = 1
In C, all intermediates that are smaller than int are automatically promoted to int.
Therefore, your char is being promoted to larger than 8 bits.
So your 0000 1010 is being shifted up by 5 bits to get 320. (nothing is shifted off the top)
If you want to rotate, you need to do two shifts and a mask:
unsigned char x = 10;
x = (x << 5) | (x >> 3);
x &= 0xff;
printf("%d", x);
It's possible to do it faster using inline assembly or if the compiler supports it, intrinsics.
Mysticial is right. If you do
char x = 10;
printf("%c", x);
It prints "#", which, if you check your ASCII table, is 64.
0000 1010 << 5 = 0001 0100 0000
You had overflow, but since it was promoted to an int, it just printed the number.
Because what you describe is a rotate, not a shift. 0 is always shifted in on left shifts.

Resources