I am essentially trying to use a union to cast a structure of data pieces with varying bit-widths into a nice clean array of integers. I have written a small program to illustrate my issue.
#include <stdio.h>
#include <iostream.h>
union {
struct {
long blah1;
short blah2;
long blah3;
short blah4;
int blah5;
} data;
int buffer[6];
} db;
int main(int argc, char* argv)
{
db.data.blah1 = 0x1111111111111111;
db.data.blah2 = 0x2222;
db.data.blah3 = 0x3333333333333333;
db.data.blah4 = 0x4444;
db.data.blah5 = 0x55555555;
for(int i=0;i<6;i++) cout << "Word " << i << ": " << std::hex << db.buffer[i] << endl;
}
Output:
Word 0: 11111111
Word 1: 11111111
Word 2: 2222
Word 3: 0
Word 4: 33333333
Word 5: 33333333
Expected Output:
Word 0: 11111111
Word 1: 11111111
Word 2: 33332222
Word 3: 33333333
Word 4: 44443333
Word 5: 55555555
I compiled using gcc version 4.1.2 20080704 (Red Hat 4.1.2-54)
Do I have something formatted incorrectly or am I trying to use this functionality for something other than it was intended? Is there another way to achieve my expected output without having to use bit-wise manipulation and endless shifting?
As pointed out by #happydave and Floris, result could be achieved by using pragma pack with value 1 to stop padding introduced for bit alignment.
#include <stdio.h>
#include <iostream>
using namespace std;
#pragma pack(push,1)
union {
struct {
long blah1;
short blah2;
long blah3;
short blah4;
int blah5;
} data;
int buffer[6];
} db;
#pragma pack(pop)
int main(int argc, char** argv)
{
db.data.blah1 = 0x1111111111111111;
db.data.blah2 = 0x2222;
db.data.blah3 = 0x3333333333333333;
db.data.blah4 = 0x4444;
db.data.blah5 = 0x55555555;
for(int i=0;i<6;i++) cout << "Word " << i << ": " << std::hex << db.buffer[i] << endl;
}
Related
I am writing a little program that reads a disk image file in binary and then checks its partition entry tables to display each partition, it's type, start sector and size.
So far it reads the first 16 bytes accurately but the rest of the partition entries are not recognized or have some kind of error.
The result looks like this:
EDIT: The first line of the output is supposed to look like this:
`Partition 0: Type: FAT-16 Start: 63 Size: 518760`
What am I missing? How do I fix the code so that all the partition entries give the appropriate result?
using namespace std;
#include <iostream>
#include <fstream>
struct Partition { char type; int start_sect; int size; } part_entry[4]; // 4 x partition table entry
int main(int argc, char *argv[])
{
//DECLARATIONS
int i, offset = 26, not_exist = 0;
char buf_part_table[64], vol_type[12];
char* diskdata;
int n;
streampos begin, end;
ifstream diskimage;
diskimage.open("Sample_1.dd", ios::in | ios::binary | ios::out);
diskdata = new char[begin];
begin = diskimage.tellg();
diskdata = new char[begin];
diskimage.seekg(446, ios::beg);
diskimage.read(buf_part_table, 64);
for (i = 0; i < 4; i++)
{
part_entry[i].type = *(char*)(buf_part_table + 0x04 + (i * offset));
if (part_entry[i].type == 0) not_exist++;
part_entry[i].start_sect = *(int*)(buf_part_table + 0x08 + (i * offset));
part_entry[i].size = *(int*)(buf_part_table + 0x0C + (i * offset));
switch (part_entry[i].type)
{
case 00: strcpy(vol_type, "NOT-VALID");
break;
case 06: strcpy(vol_type, "FAT-16");
break;
case 07: strcpy(vol_type, "NTFS");
break;
case 0x0B: strcpy(vol_type, "FAT-32");
break;
default: strcpy(vol_type, "NOT-DECODED");
break;
}
cout << "Partition " << i << ":" << " Type:" << vol_type << " Start: " << part_entry[i].start_sect << " Size: " << part_entry[i].size << endl;
}
return 0;
}
You unnecesary made program unreadable and harder to debug.
You can read whole boot sector at once and than display desired content.
Here is my quick example (it does not check if file exists, some may complain it should use memcpy for some fields etc.)
#include <iostream>
#include <fstream>
#include <cstdint>
#include <cstddef>
#include <iomanip>
using namespace std;
struct partition_t {
uint8_t status;
uint8_t start_CHS[3];
uint8_t type;
uint8_t end_CHS[3];
uint32_t start_LBA;
uint32_t size_LBA;
} __attribute__((packed));
struct mbr_t
{
uint8_t bootstrap[446];
partition_t partitions[4];
uint16_t signature;
} __attribute__((packed));
int main(int argc, char *argv[])
{
mbr_t mbr;
ifstream diskimage;
diskimage.open( "/tmp/mbr.dd", ios::in | ios::binary );
diskimage.read( reinterpret_cast<char*>(&mbr), sizeof(mbr) );
diskimage.close();
for( int idx = 0 ; idx < 4 ; idx++ )
{
string bootable = (mbr.partitions[idx].status == 128) ? "yes" : "no";
cout << " bootable : " << setw(5) << bootable <<
" type : " << setw(5) << (int)mbr.partitions[idx].type <<
" start LBA : " << setw(10) << mbr.partitions[idx].start_LBA <<
" size : " << setw(10) << mbr.partitions[idx].size_LBA << endl;
}
return 0;
}
It is easier to read, right?
I'm trying to read in formatted hex data into unsigned ints using the >> operator. The code I'm using is
#include <iostream>
#include <fstream>
int main(int argc, char** argv)
{
ifstream in(argv[1]);
unsigned int addr;
unsigned int op;
unsigned int data;
do
{
in >> hex >> addr >> hex >> op >> hex >> data;
cout << addr << " " << op << " " << data << '\n';
if (in.eof()) break;
} while(1);
return 0;
}
This works on a 300 line file just fine, but when I try it on a different file, it reads the 5th line repeatedly then seg faults, and I cannot figure out why. The first five lines are
FD2C FF EB
4FE9 FF 32
276E FF 6E
5C09 FF A3
7739 FF 36
The offending line is
7739 FF 36
Any help is appreciated. Thanks!
Edit:
I modified my code so it looks like
#include <iostream>
#include <fstream>
int main(int argc, char** argv)
{
ifstream in(argv[1]);
unsigned int addr;
unsigned int op;
unsigned int data;
while (in >> hex >> addr >> hex >> op >> hex >> data)
{
cout << addr << " " << op << " " << data << '\n';
}
return 0;
}
This solves the problem of reading the 5th line over and over again but it still segfaults, albeit on another line. I'm going to look further and see if I can pin it down.
FF is new page symbol and then it is followed by a dollar sign $ which is 36, maybe it thinks that 36 is a pointer to something. try to change unsigned int to unsigned char.
EDIT: this reads everything in without problems and output is in hex values good luck.
#include <iostream>
#include <fstream>
int main(int argc, char** argv)
{
std::ifstream in; in.open("tst.tst",std::ios::in);
unsigned char addr;
unsigned char op;
unsigned char data;
while (in >>std::hex>> addr>>std::hex>> op>>std::hex>> data)
{
std::cout << (int)addr <<std::hex << " " << (int)op<<std::hex << " " << (int)data<<std::hex<< "\n";
}
return 0;
}
I am trying to read command line argument into a fixed size unsigned char array. I get segmentation fault.
My code:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <memory.h>
unsigned char key[16]={};
int main(int argc, char** argv){
std::cout << "Hello!" << std::endl;
long a = atol(argv[1]);
std::cout << a << std::endl;
memcpy(key, (unsigned char*) a, sizeof key);
// std::cout << sizeof key << std::endl;
// for (int i = 0; i < 16; i++)
// std::cout << (int) (key[i]) << std::endl;
return 0;
}
What am I doing wrong?
To call the program:
compile: g++ main.cpp
Execute: ./a.out 128
You get SEGV because your address is wrong: you convert a value to an address. Plus the size is the one of the destination, should be the size of the source
The compiler issues a warning, that's never good, you should take it into account because that was exactly your error:
xxx.c:12:38: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
memcpy(key, (unsigned char*) a, sizeof key);
^
fix that like this:
memcpy(key, &a, sizeof(a));
BTW you don't have to declare key with 16 bytes. It would be safer to allocate it like this:
unsigned char key[sizeof(long)];
and when you print the bytes, iterate until sizeof(long) too, or you'll just print trash bytes in the end.
Here's a fix proposal using uint64_t (unsigned 64-bit integer from stdint.h which gives exact control on the size), zero initialization for your key and parsing using strtoll:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <memory.h>
#include <stdint.h>
unsigned char key[sizeof(uint64_t)]={0};
int main(int argc, char** argv){
std::cout << "Hello!" << std::endl;
uint64_t a = strtoll(argv[1],NULL,10);
memcpy(key, &a, sizeof a);
for (int i = 0; i < sizeof(key); i++)
std::cout << (int) (key[i]) << std::endl;
return 0;
}
(if you want to handle signed, just change to int64_t)
Test on a little endian architecture:
% a 10000000000000
Hello!
0
160
114
78
24
9
0
0
Looks like you are copying too much data.
I also added a &a for the memcpy.
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <memory.h>
unsigned char key[16]={};
int main(int argc, char** argv)
{
memset(key,0x0, sizeof(key));
std::cout << "Hello!" << std::endl;
long a = atol(argv[1]);
std::cout << a << std::endl;
// the size parameter needs to be the size of a
// or the lesser of the size of key and a
memcpy(key,(void *) &a, sizeof(a));
std::cout << "size of key " << sizeof(key) << "\n";
std::cout << "key " << key << "\n";
for (int i = 0; i < 16; i++)
std::cout << " " << i << " '" << ((int) key[i]) << "'\n";
return 0;
}
#include <iostream>
#include <string>
#include <bitset>
int main()
{
char c = 128;
unsigned int shift2 = (unsigned int)c;
std::string shift2bin = std::bitset<8>(shift2).to_string(); //to binary
std::cout << " shift2bin: " << shift2bin << std::endl;
unsigned int shift3 = shift2 >> 1;
std::string shift3bin = std::bitset<8>(shift3).to_string(); //to binary
std::cout << " shift3bin: " << shift3bin << std::endl;
}
Output:
shift2bin: 10000000
shift3bin: 11000000
I expect the result to be as follows:
shift2bin: 10000000
shift3bin: 01000000
Question> Why unsigned int right shift uses 1 as the filler?
As seen in this answer, unsigned right shifts always zero-fill. However, try this to print out all the bits in the unsigned int:
std::string shift2bin = std::bitset<sizeof(shift2)*8>(shift2).to_string(); //to binary
std::cout << " shift2bin: " << shift2bin << std::endl;
You will see something like (as you appear to have char signed by default):
shift2bin: 11111111111111111111111110000000
^^^^^^^^
If you do the same for shift3bin, you will see:
shift3bin: 01111111111111111111111111000000
^^^^^^^^
So, you can see how you appear to get a "1" fill.
I want to output an int in 32-bit binary format. Is looping and shifting my only option?
Looping is a way. You can also use bitset library.
#include <iostream>
#include <bitset>
int main(int argc, char** argv) {
int i = -5, j = 5;
unsigned k = 4000000000; // 4 billion
std::cout << std::bitset<32>(i) << "\t" << std::bitset<32>(j) << std::endl;
std::cout << std::bitset<32>(k) << std::endl;
return 0;
}
And the output will be:
11111111111111111111111111111011 00000000000000000000000000000101
11101110011010110010100000000000