Writing 4 bits to a binary file with ofstream - c++

If I have an unsigned integer between 0 - 16 and I want to write it to a binary file without writing a whole byte to it, how would one shift bits to achieve it?
0-16 means I only need 4 bits, so I should be able to store 2 different numbers in a single byte right?
The following code writes 1 number to 1 byte:
std::ofstream file;
file.open("test.bin", std::ios::binary|std::ios::out);
char oneByteNum = (char)fourByteNum; // Converting from some 4 byte integer to a 1 byte char
file.write(&oneByteNum ,sizeof(char));
Using bitshifts, how can I achieve 2 numbers in 1 byte?
I imagine reading the number out of the byte would be a similar, inverse 2 step process too?

char oneByteWithTwoNums = (oneByteNum1 << 4) + (oneByteNum2 & 0x0f);

Try this:
compacted = first_number * 0x10 + second-number;
To expand:
second_number = compacted & 0x0F;
first_number = compacted >> 4;

I wrote up a quick example:
#include <iostream>
typedef unsigned char byte;
byte pack(unsigned int num1, unsigned int num2) {
// Our byte has the form 0b00000000
// We want the first four bits to be filled with num1
byte packed = num1 << 4;
// We want the last four bits to be filled with num2
// but, we don't want to overwrite the top four bits, so
// we mask it with 0x0F (0b0001111)
packed |= num2 & 0x0F;
return packed;
}
void unpack(byte b, unsigned int& num1, unsigned int& num2) {
// Extract the first four bits of our byte
num1 = b >> 4;
// Mask off the first four bits of our byte to get only
// the last four bits
num2 = b & 0x0F;
}
int main() {
unsigned int num1 = 5; // As an example
unsigned int num2 = 15; // As an example
byte b = pack(num1, num2);
unsigned int num3;
unsigned int num4;
unpack(b, num3, num4);
std::cout << num3 << std::endl;
std::cout << num4 << std::endl;
return 0;
}
You'll probably want to add checks in your pack/unpack methods to ensure someone doesn't try passing in a value other than [0-15].

Related

Inserting a byte into a mutli byte type by index

I have found this answer to a similar question where one can extract a byte from a larger type. What I would like to know is what would be the reverse of this procedure by the use of an index value?
To extract a byte from a 32bit type user Pete Wilson gave this:
int a = (the_int >> 24) & 0xff; // high-order (leftmost) byte: bits 24-31
int b = (the_int >> 16) & 0xff; // next byte, counting from left: bits 16-23
int c = (the_int >> 8) & 0xff; // next byte, bits 8-15
int d = the_int & 0xff; // low-order byte: bits 0-7
I would like to do the opposite with an index value:
// assume int = 32bit or 4 bytes and unsigned char = 8bit or 1 byte
void insertByte( unsigned char a, unsigned int& value, unsigned idx ) {
// How to take byte and insert it into the byte position
// of value at idx where idx is [0-3] from the right
}
Here's an example by value:
unsigned char a = 0x9D;
unsigned int value = 0;
insertByte( a, value, 0 ); // value = 0x0000009D;
insertByte( a, value, 1 ); // value = 0x00009D00;
insertByte( a, value, 2 ); // value = 0x009D0000;
insertByte( a, value, 3 ); // value = 0x9D000000;
// insertByte( a, value, >3 ); // invalid index
Edit
User jamit made a good point with his question in the comments. I think at this moment because this will be the behavior of a constructor to a class template; I want to insert and replace, not insert and shift.
Example:
unsigned int value = 0x01234567;
unsigned char a = 0x9D;
insertByte( a, value, 2 );
// value = 0x019D4567
Just cast your char to an int and shift it by the required amount of bytes and add it to your value.
void insertByte( unsigned char a, int& value, unsigned int idx ) {
if(idx > 3)
return;
// Clear the value at position idx
value &= ~(0xff << (idx*8));
int tmp = a;
tmp = (tmp << (idx * 8));
// Set the value at position idx
value |= tmp;
}
To invert what you got from the other answer:
unsigned a = (the_int & 0x00ffffff) | (the_byte << 24); // set high-order byte: bits 24-31
unsigned b = (the_int & 0xff00ffff) | (the_byte << 16); // next byte, bits 16-23
unsigned c = (the_int & 0xffff00ff) | (the_byte << 8); // next byte, bits 8-15
unsigned d = (the_int & 0xffffff00) | (the_byte); // low-order byte: bits 0-7
The opposite of bitwise-and is bitwise-or, and the opposite of right-shift is left-shift. The remaining complication is to clear any old value in the byte, which is done with new masks. (If you ignore the new masks, this is a left-shift followed by a bitwise-or. Compare that to extracting the bytes with a right-shift followed by a bitwise-and.)
The current revision of user1178830's answer is a more programatic way to accomplish this.

C++ Encrypt Char with a Key and Mask

I need to write a code which encrypt a char with a special key.
I must use own key and mask with XOR operation.
But I have a problem with understanding and implementation of this.
Firstly, I created my own key which I use to encrypt a char. This key is e.q number: 123456789. In binary representation number 123456789 is: 00010101 11001101 01011011 00000111. I divided this to 4 x 8 bits because I enter a type of char.
I must use this to encrypt my char with a mask too. My mask is 0xFF because it resets the oldest bits and the youngest 8 bits are left to operate with XOR operation.
It means when I enter char "a" it should encrypt this with this key and a mask with XOR operation.
What's more, I wanted to check what my compilator shows with key[0] position. It means I have "int key[0] = {00000111}" As I think it should show a number of 7 as a binary number, but compilator shows number 73. Why?
I would appreciate if somebody can help me to resolve this problem.
Here is my code:
#include <iostream>
using namespace std;
void encryption(char chars[], const int size);
int main() {
const int size1 = 4;
char chars1[size1];
unsigned int keys = 123456789;
int key[] = {00000111}; // why does it show number 73 instead of 7 ?
cout << "Enter a char to encrypt: " << endl;
cin >> chars1[0];
return 0; }
void encryption(char chars[], const int size) {
unsigned int keys = 123456789;
unsigned int key[] = {00010101, 11001101, 01011011, 00000111};
unsigned int mask = 0xFF;
int temp[4] = {0};
temp[0] = chars[0] ^ (keys & mask);
temp[1] = chars[0] ^ ((keys >> 8) & mask);
temp[2] = chars[0] ^ ((keys >> 16) & mask);
temp[3] = chars[0] ^ ((keys >> 24) & mask);
}
There are several problems:
unsigned int keys = 123456789 is in hex 075bcd15
00010101, 11001101, 01011011, 00000111 is in hex 15cd5b07
While both are 4-bytes notice the reverse order of the bytes, that is because the computer used what is known as little-endian byte order for integers. So if you get the bytes by casting to an unsigned character you will get the reversed byte order from what you expect.
unsigned int key[] is an array of int which seem to be 32-bits (4-bytes).
For a single unsigned int use
unsigned int keyBytes3 = {0x075bcd15};
For an array of 4 unsigned char:
unsigned char keyBytes[] = {0x07, 0x5b, 0xcd, 0x15};
Personally for instances where size matters I prefer using uint32_t and uint8_t types, then it is clear of the sizes, int may be larger or smaller the 32-bits depending on the CPU.
The problem is that the compiler does not interpret your 00000111as binary. C++ 11 does not support binary literals. In addition, any number that starts with 0 (aka 00000111) as the most-significant digit is considered to be in octal. In octal, 111 is the equivalent of 73 in decimal.
You'll need to convert all of your "binary values" to decimal, then use those. Or you could use boost, which has a utility that handles what you're looking to do.

Getting shorts from an integer

I'm supposed to pack some shorts into a 32 bit integer. It's a homework assignment that will lead into a larger idea of compression/decompression.
I don't have any problems understanding how to pack the shorts into an integer, but I am struggling to understand how to get each short value stored within the integer.
So, for example, I store the values 2, 4, 6, 8 into the integer. That means I want to print them in the same order I input them.
How do you go about getting these values out from the integer?
EDIT: Shorts in this context refers to an unsigned two-byte integer.
As Craig corrected me, short is a 16 bit variable, therfore only 2 shorts can fit in one int, so here's my answer retrieving shorts:
2|4
000000000000001|00000000000000100
00000000000000100000000000000100
131076
denoting first as the left-most variable and last as the right-most variable, getting the short variable would like like this:
int x = 131076; //00000000000000100000000000000100 in binary
short last = x & 65535; // 65535= 1111111111111111
short first= (x >> 16) & 65535;
and here's my previous answer fixed for compressing chars (8 bit variables):
Let's assume the first char is the one the start on the MSB and the last one is the one that ends on the LSB:
2|4|6|8
00000001|00000010|000000110|00001000
000000010000001000000011000001000
33818120
So, in this example the first char is 2 (0010), followed by 4 (0100), 6 (0110) and last: 8 (1000).
so to get the compressed numbers back one could use this code:
int x = 33818120; //00000010000001000000011000001000 in binary
char last = x & 255; // 255= 11111111
char third = (x >> 8) & 255;
char second = (x >> 16) & 255;
char last = (x >> 24) & 255;
This would be more interesting with char [as you'd get 4]. But, you can only pack two shorts into a single int. So, I'm a bit mystified by this as to what the instructor was thinking.
Consider a union:
union combo {
int u_int;
short u_short[2];
char u_char[4];
};
int
getint1(short s1,short s2)
{
union combo combo;
combo.u_short[0] = s1;
combo.u_short[1] = s2;
return combo.u_int;
}
short
getshort1(int val,int which)
{
union combo combo;
combo.u_int = val;
return combo.u_short[which];
}
Now consider encoding/decoding with shifts:
unsigned int
getint2(unsigned short s1,unsigned short s2)
{
unsigned int val;
val = s1;
val <<= 16;
val |= s2;
return val;
}
unsigned short
getshort2(unsigned int val,int which)
{
val >>= (which * 16);
return val & 0xFFFF;
}
The unsigned code above will probably do what you want.
But, the next uses signed values and probably won't work as well because you may have mixed signs between s1/s2 and encoding/decoding that may present problems
int
getint3(short s1,short s2)
{
int val;
val = s1;
val <<= 16;
val |= s2;
return val;
}
short
getshort3(int val,int which)
{
val >>= (which * 16);
return val & 0xFFFF;
}

C++ write a number on two bytes

I am new to the low level c++, and I find it a bit hard to understand how to manipulate bits. I am trying to do the following to use in a compression algorithm I am trying to make:
unsigned int num = ...;//we want to store this number
unsigned int num_size = 3;//this is the maximum size of the number in bits, and
//can be anything from 1 bit to 32
unsigned int pos = 7;//the starting pos on the 1st bit.
//this can be anything from 1 to 8
char a;
char b;
if the num_size is 3 and pos is 7 for example, we must store num, on the 7th and 8th bit of a and on the 1st bit of b.
How about just?
a = num << (pos-1);
b = ((num << (pos-1)) & 0xFF00) >> 8;
To read num back just
num = ((unsigned int)a + ((unsigned int b) << 8)) >> (pos - 1);
Note, this doesn't do any sanity checks, such as whether all the relevant bits fit in a and b, you'll have to do that yourself.
For this specific test case, the highest number that fits into 2 unsigned char is actually 65535.
#include <iostream>
unsigned char high(int input)
{
return (input >> 8) & 0xFF;
}
unsigned char low(int input)
{
return input & 0xFF;
}
int value(unsigned char low, unsigned char high)
{
return low | (high << 8);
}
int main()
{
int num = 65535;
unsigned char l = low(num);
unsigned char h = high(num);
int val = value(l, h);
std::cout<<"l: "<<l<<" h: "<<h<<" val: "<<val;
}

Integer Byte Swapping in C++

I'm working on a homework assignment for my C++ class. The question I am working on reads as follows:
Write a function that takes an unsigned short int (2 bytes) and swaps the bytes. For example, if the x = 258 ( 00000001 00000010 ) after the swap, x will be 513 ( 00000010 00000001 ).
Here is my code so far:
#include <iostream>
using namespace std;
unsigned short int ByteSwap(unsigned short int *x);
int main()
{
unsigned short int x = 258;
ByteSwap(&x);
cout << endl << x << endl;
system("pause");
return 0;
}
and
unsigned short int ByteSwap(unsigned short int *x)
{
long s;
long byte1[8], byte2[8];
for (int i = 0; i < 16; i++)
{
s = (*x >> i)%2;
if(i < 8)
{
byte1[i] = s;
cout << byte1[i];
}
if(i == 8)
cout << " ";
if(i >= 8)
{
byte2[i-8] = s;
cout << byte2[i];
}
}
//Here I need to swap the two bytes
return *x;
}
My code has two problems I am hoping you can help me solve.
For some reason both of my bytes are 01000000
I really am not sure how I would swap the bytes. My teachers notes on bit manipulation are very broken and hard to follow and do not make much sense me.
Thank you very much in advance. I truly appreciate you helping me.
New in C++23:
The standard library now has a function that provides exactly this facility:
#include <iostream>
#include <bit>
int main() {
unsigned short x = 258;
x = std::byteswap(x);
std::cout << x << endl;
}
Original Answer:
I think you're overcomplicating it, if we assume a short consists of 2 bytes (16 bits), all you need
to do is
extract the high byte hibyte = (x & 0xff00) >> 8;
extract the low byte lobyte = (x & 0xff);
combine them in the reverse order x = lobyte << 8 | hibyte;
It looks like you are trying to swap them a single bit at a time. That's a bit... crazy. What you need to do is isolate the 2 bytes and then just do some shifting. Let's break it down:
uint16_t x = 258;
uint16_t hi = (x & 0xff00); // isolate the upper byte with the AND operator
uint16_t lo = (x & 0xff); // isolate the lower byte with the AND operator
Now you just need to recombine them in the opposite order:
uint16_t y = (lo << 8); // shift the lower byte to the high position and assign it to y
y |= (hi >> 8); // OR in the upper half, into the low position
Of course this can be done in less steps. For example:
uint16_t y = (lo << 8) | (hi >> 8);
Or to swap without using any temporary variables:
uint16_t y = ((x & 0xff) << 8) | ((x & 0xff00) >> 8);
You're making hard work of that.
You only neeed exchange the bytes. So work out how to extract the two byte values, then how to re-assemble them the other way around
(homework so no full answer given)
EDIT: Not sure why I bothered :) Usefulness of an answer to a homework question is measured by how much the OP (and maybe other readers) learn, which isn't maximized by giving the answer to the homewortk question directly...
Here is an unrolled example to demonstrate byte by byte:
unsigned int swap_bytes(unsigned int original_value)
{
unsigned int new_value = 0; // Start with a known value.
unsigned int byte; // Temporary variable.
// Copy the lowest order byte from the original to
// the new value:
byte = original_value & 0xFF; // Keep only the lowest byte from original value.
new_value = new_value * 0x100; // Shift one byte left to make room for a new byte.
new_value |= byte; // Put the byte, from original, into new value.
// For the next byte, shift the original value by one byte
// and repeat the process:
original_value = original_value >> 8; // 8 bits per byte.
byte = original_value & 0xFF; // Keep only the lowest byte from original value.
new_value = new_value * 0x100; // Shift one byte left to make room for a new byte.
new_value |= byte; // Put the byte, from original, into new value.
//...
return new_value;
}
Ugly implementation of Jerry's suggestion to treat the short as an array of two bytes:
#include <iostream>
typedef union mini
{
unsigned char b[2];
short s;
} micro;
int main()
{
micro x;
x.s = 258;
unsigned char tmp = x.b[0];
x.b[0] = x.b[1];
x.b[1] = tmp;
std::cout << x.s << std::endl;
}
Using library functions, the following code may be useful (in a non-homework context):
unsigned long swap_bytes_with_value_size(unsigned long value, unsigned int value_size) {
switch (value_size) {
case sizeof(char):
return value;
case sizeof(short):
return _byteswap_ushort(static_cast<unsigned short>(value));
case sizeof(int):
return _byteswap_ulong(value);
case sizeof(long long):
return static_cast<unsigned long>(_byteswap_uint64(value));
default:
printf("Invalid value size");
return 0;
}
}
The byte swapping functions are defined in stdlib.h at least when using the MinGW toolchain.
#include <stdio.h>
int main()
{
unsigned short a = 258;
a = (a>>8)|((a&0xff)<<8);
printf("%d",a);
}
While you can do this with bit manipulation, you can also do without, if you prefer. Either way, you shouldn't need any loops though. To do it without bit manipulation, you'd view the short as an array of two chars, and swap the two chars, in roughly the same way as you would swap two items while (for example) sorting an array.
To do it with bit manipulation, the swapped version is basically the lower byte shifted left 8 bits ord with the upper half shifted left 8 bits. You'll probably want to treat it as an unsigned type though, to ensure the upper half doesn't get filled with one bits when you do the right shift.
This should also work for you.
#include <iostream>
int main() {
unsigned int i = 0xCCFF;
std::cout << std::hex << i << std::endl;
i = ( ((i<<8) & 0xFFFF) | ((i >>8) & 0xFFFF)); // swaps the bytes
std::cout << std::hex << i << std::endl;
}
A bit old fashioned, but still a good bit of fun.
XOR swap: ( see How does XOR variable swapping work? )
#include <iostream>
#include <stdint.h>
int main()
{
uint16_t x = 0x1234;
uint8_t *a = reinterpret_cast<uint8_t*>(&x);
std::cout << std::hex << x << std::endl;
*(a+0) ^= *(a+1) ^= *(a+0) ^= *(a+1);
std::cout << std::hex << x << std::endl;
}
This is a problem:
byte2[i-8] = s;
cout << byte2[i];//<--should be i-8 as well
This is causing a buffer overrun.
However, that's not a great way to do it. Look into the bit shift operators << and >>.