i'm trying to read from a binary file to a char array. When printing array entries, an arbitrary number (newline) and the desired number are being printed. I really cant get my head around this.
The first few bytes of the file are:
00 00 08 03 00 00 EA 60 00 00 00 1C 00 00 00 1C 00 00
My Code:
void MNISTreader::loadImagesAndLabelsToMemory(std::string imagesPath,
std::string labelsPath) {
std::ifstream is(imagesPath.c_str());
char *data = new char[12];
is.read(data, 12);
std::cout << std::hex << (int)data[2] << std::endl;
delete [] data;
is.close();
}
E.g it prints:
ffffff9b
8
8 is correct. The preceding number changes from execution to execution. And where does this newline come from?
You asked about reading data from a binary file and saving it into a char[] and you showed us this code that you submitted for your question:
void MNISTreader::loadImagesAndLabelsToMemory(std::string imagesPath,
std::string labelsPath) {
std::ifstream is(imagesPath.c_str());
char *data = new char[12];
is.read(data, 12);
std::cout << std::hex << (int)data[2] << std::endl;
delete [] data;
is.close();
}
And you wanted to know:
The preceding number changes from execution to execution. And where does this newline come from?
Before you can actually answer that question you need to know the binary file. That is what is the structure of the file internally. When you are reading data from a binary you have to remember that some program had written data to that file and that data was written in a structured format. It is this format that is unique to each family or file type of binary that is important. Most binaries will usually follow a common pattern such that they would container a header then maybe even sub headers then either clusters, or packets or chunks, etc. or even raw data after the header while some binaries may just be purely raw data. You have to know how the file is structured in memory.
What is the structure of the data?
Is the data type for the first entry into the file a char = 1 byte, int = 4 bytes (32bit system) 8 bytes (64bit system), float = 4bytes, double = 8bytes, etc.
According to your code you have an array of char with a size of 12 and knowing that a char is 1 byte in memory you are asking for 12 bytes. Now the problem here is that you are pulling off 12 consecutive individual bytes in a row and by not knowing the file structure how can you determine if the first byte was an actual char written or an unsigned char, or a int?
Consider these two different binary file structures that are created by C++ structs that contains all the needed data and both are written out to a file in a binary format.
A Generic Header Structure that both File Structures will use.
struct Header {
// Size of Header
std::string filepath;
std::string filename;
unsigned int pathSize;
unsigned int filenameSize;
unsigned int headerSize;
unsigned int dataSizeInBytes;
};
FileA Unique Structure For File A
struct DataA {
float width;
float length;
float height;
float dummy;
}
FileB Unique Structure For File B
struct DataB {
double length;
double width;
}
A File in memory in general would be something like this:
First Few Bytes are the path and file name and stored sizes
This can vary from file to file depending on how many characters
are used for both the file path and file name.
After the strings we do know that the next 4 data types are unsigned
so we know that on a 32bit system it will be 4bytes x 4 = 16 total bytes
For a 64bit system it will be 8bytes x 4 = 32 total bytes.
If we know the system architecture then we can get past this easily enough.
Of these 4 unsigned(s) the first two are for the length of the path and filename. Now these could be the first two read in from the file and not the actual paths. The order of these could be reversed.
It is the next 2 unsigned(s) that are of importance
The next is the full size of the header and can be used to read in and skip over the header.
The next one tells you the size of the data to be pulled in now these could be in chunks with a count of how many chunks because it could be a series of the same data structures but for simplicity I left out chunks and counts and using a single instance structure.
It is here were we can then extract the amount of data in bytes by how many bytes to extract.
Lets consider the two different binary files where we are already past all the header information and we are reading in the bytes to parse. We get to the size of the data in bytes and for FileA we have 4 floats = 16bytes and for FileB we have 2 doubles = 16bytes. So now we know how to call the method to read in x amount of data for a y type of data. Since y is now a type and x is amount of we can say this: y(x) As if y is a built in type and x is a numerical initializer for the default built in type of constructor for this built in type either it be an int, float, double, char, etc.
Now let's say we were reading in either one of these two files but didn't know the data structure and how its information was previously stored to the file and we are seeing by the header that the data size is 16 bytes in memory but we didn't know if it was being stored as either 4 floats = 16 bytes or 2 doubles = 16 bytes. Both structures are 16 bytes but have a different amount of different data types.
The summation of this is that without knowing the file's data structure and knowing how to parse the binary does become an X/Y Problem
Now let's assume that you do know the file structure to try and answer your question from above you can try this little program and to check out some results:
#include <string>
#include <iostream>
int main() {
// Using Two Strings
std::string imagesPath("ImagesPath\\");
std::string labelsPath("LabelsPath\\");
// Concat of Two Strings
std::string full = imagesPath + labelsPath;
// Display Of Both
std::cout << full << std::endl;
// Data Type Pointers
char* cData = nullptr;
cData = new char[12];
unsigned char* ucData = nullptr;
ucData = new unsigned char[12];
// Loop To Set Both Pointers To The String
unsigned n = 0;
for (; n < 12; ++n) {
cData[n] = full.at(n);
ucData[n] = full.at(n);
}
// Display Of Both Strings By Character and Unsigned Character
n = 0;
for (; n < 12; ++n) {
std::cout << cData[n];
}
std::cout << std::endl;
n = 0;
for (; n < 12; ++n) {
std::cout << ucData[n];
}
std::cout << std::endl;
// Both Yeilds Same Result
// Okay lets clear out the memory of these pointers and then reuse them.
delete[] cData;
delete[] ucData;
cData = nullptr;
ucData = nullptr;
// Create Two Data Structurs 1 For Each Different File
struct A {
float length;
float width;
float height;
float padding;
};
struct B {
double length;
double width;
};
// Constants For Our Data Structure Sizes
const unsigned sizeOfA = sizeof(A);
const unsigned sizeOfB = sizeof(B);
// Create And Populate An Instance Of Each
A a;
a.length = 3.0f;
a.width = 3.0f;
a.height = 3.0f;
a.padding = 0.0f;
B b;
b.length = 5.0;
b.width = 5.0;
// Lets First Use The `Char[]` Method for each struct and print them
// but we need 16 bytes instead of `12` from your problem
char *aData = nullptr; // FileA
char *bData = nullptr; // FileB
aData = new char[16];
bData = new char[16];
// Since A has 4 floats we know that each float is 4 and 16 / 4 = 4
aData[0] = a.length;
aData[4] = a.width;
aData[8] = a.height;
aData[12] = a.padding;
// Print Out Result but by individual bytes without casting for A
// Don't worry about the compiler warnings and build and run with the
// warning and compare the differences in what is shown on the screen
// between A & B.
n = 0;
for (; n < 16; ++n) {
std::cout << aData[n] << " ";
}
std::cout << std::endl;
// Since B has 2 doubles weknow that each double is 8 and 16 / 8 = 2
bData[0] = b.length;
bData[8] = b.width;
// Print out Result but by individual bytes without casting for B
n = 0;
for (; n < 16; ++n) {
std::cout << bData[n] << " ";
}
std::cout << std::endl;
// Let's Print Out Both Again But By Casting To Their Approriate Types
n = 0;
for (; n < 4; ++n) {
std::cout << reinterpret_cast<float*>(aData[n]) << " ";
}
std::cout << std::endl;
n = 0;
for (; n < 2; ++n) {
std::cout << reinterpret_cast<double*>(bData[n]) << " ";
}
std::cout << std::endl;
// Clean Up Memory
delete[] aData;
delete[] bData;
aData = nullptr;
bData = nullptr;
// Even By Knowing The Appropriate Sizes We Can See A Difference
// In The Stored Data Types. We Can Now Do The Same As Above
// But With Unsigned Char & See If It Makes A Difference.
unsigned char *ucAData = nullptr;
unsigned char *ucBData = nullptr;
ucAData = new unsigned char[16];
ucBData = new unsigned char[16];
// Since A has 4 floats we know that each float is 4 and 16 / 4 = 4
ucAData[0] = a.length;
ucAData[4] = a.width;
ucAData[8] = a.height;
ucAData[12] = a.padding;
// Print Out Result but by individual bytes without casting for A
// Don't worry about the compiler warnings and build and run with the
// warning and compare the differences in what is shown on the screen
// between A & B.
n = 0;
for (; n < 16; ++n) {
std::cout << ucAData[n] << " ";
}
std::cout << std::endl;
// Since B has 2 doubles weknow that each double is 8 and 16 / 8 = 2
ucBData[0] = b.length;
ucBData[8] = b.width;
// Print out Result but by individual bytes without casting for B
n = 0;
for (; n < 16; ++n) {
std::cout << ucBData[n] << " ";
}
std::cout << std::endl;
// Let's Print Out Both Again But By Casting To Their Approriate Types
n = 0;
for (; n < 4; ++n) {
std::cout << reinterpret_cast<float*>(ucAData[n]) << " ";
}
std::cout << std::endl;
n = 0;
for (; n < 2; ++n) {
std::cout << reinterpret_cast<double*>(ucBData[n]) << " ";
}
std::cout << std::endl;
// Clean Up Memory
delete[] ucAData;
delete[] ucBData;
ucAData = nullptr;
ucBData = nullptr;
// So Even Changing From `char` to an `unsigned char` doesn't help here even
// with reinterpret casting. Because These 2 Files Are Different From One Another.
// They have a unique signature. Now a family of files where a specific application
// saves its data to a binary will all follow the same structure. Without knowing
// the structure of the binary file and knowing how much data to pull in and the big key
// word here is `what type` of data you are reading in and by how much. This becomes an (X/Y) Problem.
// This is the hard part about parsing binaries, you need to know the file structure.
char c = ' ';
std::cin.get(c);
return 0;
}
After running the short program above don't worry about what each value being displayed to the screen is; just look at the patterns that are there for the comparison of the two different file structures. This is just to show that a struct of floats that is 16 bytes wide is not the same as a struct of doubles that is also 16 bytes wide. So when we go back to your problem and you are reading in 12 individual consecutive bytes the question then becomes what does these first 12 bytes represent? Is it 3 ints or 3 unsigned ints if on 32bit machine or 2 ints or 2 unsigned ints on a 64bit machine, or 3 floats, or is a combination such as 2 doubles and 1 float? What is the current data structure of the binary file you are reading in?
Edit In my little program that I wrote; I did forget to try or add in the << std::hex << in the print out statements they can be added in as well were each printing of the index pointers are used but there is no need to do so because the output to the display is the same exact thing as this only shows or expresses visually the difference of the two data structures in memory and what their patterns look like.
Related
I want to store integers in char array ex: 0 up to 1449, I checked other posts and I tried memset, sprinf etc. but either I get gibberish characters or unreadable symbols when I print inside of char array. Can anyone help please?
I checked the duplicate link however I am not trying to print int to char, I want to store int in char array. But I tried buf[i] = static_cast<char>(i); inside for loop but it didn't work. Casting didn't work.
The last one I tried is like this:
char buf[1450];
for (int i = 0; i < 1449; i++)
{
memset(buf, ' '+ i, 1450);
cout << buf[i];
}
The output is:
I'm not sure what you trying to do! You should say your objective.
A char (usually 8 bit) in c++ doesn't hold an int (usually 32 bit), If you want to store an int you should use an int array:
int buf[1500];
The memset(buf, ' '+ i, 1450); will actually write the sum of ' ' ascii number plus i always at beginning of the buffer (buffer address is never incremented).
something like this, maybe is what you want:
int buf[1500] = 0;
for (int i = 0; i < 1449; i++)
{
buf[i] = i;
cout << buf[i] << ' ';
}
consider using c++11 containers like std::vector to hold the int or chars, would much safer to use.
You are going to have to explain better what it is you want, because "store integers in char array" is exactly what this code does:
char buf[1450];
for (int i = 0; i < 1450; i++)
{
buf[i] = static_cast<char>(i);
std::cout << buf[i];
}
Yes, the output is similar to what your picture shows, but that is also the correct output.
When you use a debugger to look at buf after the loop, then it does contain: 0, 1, 2, 3, ..., 126, 127, -128, -127, ..., 0, 1, 2, 3, ... and so on, which is the expected contents given that we are trying to put the numbers 0-1449 into an integer type that (in this case*) can contain the range [-128;127].
If this is not the behavior you are looking for (it sounds like it isn't), then you need to describe your requirements in more detail or we won't be able to help you.
(*) Char must be able to contain a character representative. On many/most systems it is 8 bits, but the size is system dependent and it may also be larger.
New answer.
Thank you for the clarification, I believe that what you need is something like this:
int32_t before = 1093821061; // Int you want to transmit
uint8_t buf[4];
buf[0] = static_cast<uint8_t>((before >> 0) & 0xff);
buf[1] = static_cast<uint8_t>((before >> 8) & 0xff);
buf[2] = static_cast<uint8_t>((before >> 16) & 0xff);
buf[3] = static_cast<uint8_t>((before >> 24) & 0xff);
// Add buf to your UDP packet and send it
// Stuff...
// After receiving the packet on the other end:
int32_t after = 0;
after += buf[0] << 0;
after += buf[1] << 8;
after += buf[2] << 16;
after += buf[3] << 24;
std::cout << before << ", " << after << std::endl;
Your problem (as I see it), is that you want to store 32bit numbers in the 8bit buffers that you need for UDP packets. The way to do this is to pick the larger number apart, and convert it into individual bytes, transmit those bytes, and then assemble the big number again from the bytes.
The above code should allow you to do this. Note that I have changed types to int32_t and uint8_t to ensure that I know the exact size of my types - depending on the library you use, you may have to use plain int and char types, just be aware that then the exact sizes of your types are not guaranteed (most likely it will still be 32 and 8 bits, but they can change in size if you change compiler or compile for a different target system). If you want you can add some sizeof checks to ensure that your types conform to what you expect.
I have a code that looks as below:
typedef struct{
uint8_t distance[2];
uint8_t reflectivity;
}data_point;
typedef struct{
uint8_t flag[2];
uint8_t Azimuth[2];
std::vector<data_point> points; // always size is 32 but not initialized whereas filled in run-time using emplace_back
}data_block;
typedef struct{
uint8_t UDP[42];
std::vector<data_block> data; // always size is 12 but not initialized whereas filled in run-time using emplace_back
uint8_t time_stamp[4];
uint8_t factory[2];
}data_packet;
static std::vector<data_packet> packets_from_current_frame;
Assuming packets_from_current_frame.size() = 26, How can I calculate the number of bytes in packets_from_current_frame?
My solution on paper:
1 data_packet (assuming 32 points and 12 data) will have 42+ (12*(2+2+32(3))) + 4 + 2 = 1248. Hence, the end address is _begin + sizeof(uint8_t) * 26 * 1248 (_begin is the start address of the memory buffer).
With this calculation I always loose some data. Number of bytes that is lost depends on packets_from_current_frame.size(). What is wrong with the calculation?
Take a look at this code:
int main() {
static std::vector<data_packet> packets_from_current_frame;
std::cout << "sizeof data_point = " << (sizeof(data_point)) << std::endl;
std::cout << "sizeof data_block = " << (sizeof(data_block)) << std::endl;
std::cout << "sizeof data_packet = " << (sizeof(data_packet)) << std::endl;
return 0;
}
Output:
sizeof data_point = 3
sizeof data_block = 32
sizeof data_packet = 80
From this it is clear why your calculation fails.
You have forgotten to take into account things like the vector itself, fields after the vector and padding.
The correct way to calculate it is:
packets_from_current_frame.size() * (sizeof(data_packet) + data.size() * (sizeof(data_block) + points.size() * sizeof(data_point)))
Note: This amount of bytes are not stored in one consecutive memory block so don't try any direct memcpy.
The individual vector has consecutive data. If you want to know the address of the data held by a vector, use vector::data()
I was playing around with memcpy when I stumbled on a strange result, where a memcpy that is called on the same pointer of memory after bool memcpy gives unexpected result.
I created a simple test struct that has a bunch of different type variables. I cast the struct into unsigned char pointer and then using memcpy I copy data from that pointer into separate variables. I tried playing around the offset of memcpy and shifting the int memcpy before bool (changed the layout of test struct so that the int would go before the bool too). Suprisingly the shifting fixed the problem.
// Simple struct containing 3 floats
struct vector
{
float x;
float y;
float z;
};
// My test struct
struct test2
{
float a;
vector b;
bool c;
int d;
};
int main()
{
// I create my structure on the heap here and assign values
test2* test2ptr = new test2();
test2ptr->a = 50;
test2ptr->b.x = 100;
test2ptr->b.y = 101;
test2ptr->b.z = 102;
test2ptr->c = true;
test2ptr->d = 5;
// Then turn the struct into an array of single bytes
unsigned char* data = (unsigned char*)test2ptr;
// Variable for keeping track of the offset
unsigned int offset = 0;
// Variables that I want the memory copied into they
float a;
vector b;
bool c;
int d;
// I copy the memory here in the same order as it is defined in the struct
std::memcpy(&a, data, sizeof(float));
// Add the copied data size in bytes to the offset
offset += sizeof(float);
std::memcpy(&b, data + offset, sizeof(vector));
offset += sizeof(vector);
std::memcpy(&c, data + offset, sizeof(bool));
offset += sizeof(bool);
// It all works until here the results are the same as the ones I assigned
// however the int value becomes 83886080 instead of 5
// moving this above the bool memcpy (and moving the variable in the struct too) fixes the problem
std::memcpy(&d, data + offset, sizeof(int));
offset += sizeof(int);
return 0;
}
So I expected the value of d to be 5 however it becomes 83886080 which I presume is just random uninitialized memory.
You ignore the padding of your data in a struct.
Take a look on the following simplified example:
struct X
{
bool b;
int i;
};
int main()
{
X x;
std::cout << "Address of b " << (void*)(&x.b) << std::endl;
std::cout << "Address of i " << (void*)(&x.i) << std::endl;
}
This results on my PC with:
Address of b 0x7ffce023f548
Address of i 0x7ffce023f54c
As you see, the bool value in the struct takes 4 bytes here even it uses less for its content. The compiler must add padding bytes to the struct to make it possible the cpu can access the data directly. If you have the data arranged linear as written in your code, the compiler have to generate assembly instructions on all access to align the data later which slows down your program a lot.
You can force the compiler to do that by adding pragma pack or something similar with your compiler. All the pragma things are compiler specific!
For your program, you have to use the address if the data for the memcpy and not the size of the data element before the element you want to access as this ignore padding bytes.
If I add a pragma pack(1) before my program, the output is:
Address of b 0x7ffd16c79cfb
Address of i 0x7ffd16c79cfc
As you can see, there are no longer padding bytes between the bool and the int. But the code which will access i later will be very large and slow! So avoid use of #pragma pack at all!
You've got the answer you need so I'll not get into detail. I just made an extraction function with logging to make it easier to follow what's happening.
#include <cstring>
#include <iostream>
#include <memory>
// Simple struct containing 3 floats
struct vector {
float x;
float y;
float z;
};
// My test struct
struct test2 {
float a;
vector b;
bool c;
int d;
};
template<typename T>
void extract(T& dest, unsigned char* data, size_t& offset) {
std::uintptr_t dp = reinterpret_cast<std::uintptr_t>(data + offset);
size_t align_overstep = dp % alignof(T);
std::cout << "sizeof " << sizeof(T) << " alignof " << alignof(T) << " data "
<< dp << " mod " << align_overstep << "\n";
if(align_overstep) {
size_t missing = alignof(T) - align_overstep;
std::cout << "misaligned - adding " << missing << " to align it again\n";
offset += missing;
}
std::memcpy(&dest, data + offset, sizeof(dest));
offset += sizeof(dest);
}
int main() {
std::cout << std::boolalpha;
// I create my structure on the heap here and assign values
test2* test2ptr = new test2();
test2ptr->a = 50;
test2ptr->b.x = 100;
test2ptr->b.y = 101;
test2ptr->b.z = 102;
test2ptr->c = true;
test2ptr->d = 5;
// Then turn the struct into an array of single bytes
unsigned char* data = reinterpret_cast<unsigned char*>(test2ptr);
// Variable for keeping track of the offset
size_t offset = 0;
// Variables that I want the memory copied into they
float a;
vector b;
bool c;
int d;
// I copy the memory here in the same order as it is defined in the struct
extract(a, data, offset);
std::cout << "a " << a << "\n";
extract(b, data, offset);
std::cout << "b.x " << b.x << "\n";
std::cout << "b.y " << b.y << "\n";
std::cout << "b.z " << b.z << "\n";
extract(c, data, offset);
std::cout << "c " << c << "\n";
extract(d, data, offset);
std::cout << "d " << d << "\n";
std::cout << offset << "\n";
delete test2ptr;
}
Possible output
sizeof 4 alignof 4 data 12840560 mod 0
a 50
sizeof 12 alignof 4 data 12840564 mod 0
b.x 100
b.y 101
b.z 102
sizeof 1 alignof 1 data 12840576 mod 0
c true
sizeof 4 alignof 4 data 12840577 mod 1
misaligned - adding 3 to align it again
d 5
24
There are apparently three padding bytes between the bool and the subsequent int. This is allowed by the standard due to alignment considerations (accessing a 4 byte int that is not aligned on a 4 byte boundary may be slow or crash on some systems).
So when you do offset += sizeof(bool), you are not incrementing enough. The int follows 4 bytes after, not 1. The result is that the 5 is not the first byte you read but the last one - you are reading three padding bytes plus the first one from test2ptr->d into d. And it is no coincidence that 83886080 = 2^24 * 5 (the padding bytes were apparently all zeros).
A bit of Background if you are interested...
The next piece of code is an attempt at implementing a Packet Error Code generator using Cyclical Redundancy Check (CRC-15). This is used to detect communication data corruption. A more detailed introduction is unnecessary.
Code and Issues
init_PEC15_Table function is a lookup-table generator.
pec15 function takes a data input, calculates the address of the solution and find the result in the lookup-table.
data is a char array that I have assigned a value of 1 to. This is going to be passed to pec15.
Now, I found that by just reordering the cout commands, the value of "stuffed pec", which is the output I am interested in, changes. By reading online I understood that this could be due to the memory stack unexpectedly changing in a way that affects the result registers and that this could be due to out-of-bounds operations on other variables. Am I mistaken in my understanding?
Now, I am a beginner and this is very daunting. I might have made some gross mistakes that I am not aware of so please feel free to tear the code to shreds.
Also, if it matters, this code is running on an mbed LPC1768.
#include <iostream>
using namespace std;
unsigned short pec15Table[256];
const unsigned int CRC15_POLY = 0x4599;
void init_PEC15_Table() // Cyclical Redundancy Check lookup table generator function
{
unsigned short rem;
for (int i = 0; i < 256; i++)
{
rem = i << 7;
for (int bit = 8; bit > 0; --bit)
{
if (rem & 0x4000)
{
rem = ((rem << 1));
rem = (rem ^ CRC15_POLY);
}
else
{
rem = ((rem << 1));
}
}
pec15Table[i] = rem & 0xFFFF;
// cout << hex << pec15Table [i] << endl;
}
}
unsigned short pec15(char* data, int lengt = 16) //Takes data as an input,
{
int rem, address;
rem = 16;//PEC seed (intial PEC value)
for (int i = 0; i < lengt; i++)
{
address = ((rem >> 7) ^ data[i]) & 0xff;//calculate PEC table address
rem = (rem << 8) ^ pec15Table[address];
}
return (rem * 2);//The CRC15 has a 0 in the LSB so the final value must be multiplied by 2
}
int main()
{
init_PEC15_Table(); //initialise pec table
char data = (short) 0x1 ; // Write 0x1 to char array containing the data 0x1
char* dataPtr = &data; // Create a pointer to that array
unsigned short result = pec15(dataPtr); //Pass data pointer to pec calculator
cout << "data in: " << (short) *dataPtr << endl; //Print the short representation of the char data array (Outputs 1)
cout << "size of data: " << sizeof(*dataPtr) << endl; //Print the size of the char array (Outputs 1)
cout << "stuffed pec: " << result << endl; //Print the output of the pec calculation
return 0;
}
The code you've written here does not sync with the comments you've written:
char data = (short) 0x1 ; // Write 0x1 to char array containing the data 0x1
char* dataPtr = &data; // Create a pointer to that array
The first line does not write anything to a character array. Rather, it creates a char variable whose numeric value is 1. As a note, the cast to short here isn't needed and has no effect - did you mean to write something else?
The second line does not create a pointer to an array. Rather, it creates a pointer to the data variable. You could potentially think of this as a pointer to an array of length one, but that's probably not what you meant to do.
The two above lines don't by themselves do anything bad. The next line, however, is a real problem:
unsigned short result = pec15(dataPtr); //Pass data pointer to pec calculator
Remember that pec15 has a second argument that's supposed to denote the length of the data passed in. Since you didn't specify it, it defaults to 16. However, your dataPtr pointer only points to a single char value, not 16 char values, so this results in undefined behavior.
I'm not sure how to fix this because I don't have a good sense for the intent behind your code. Did you mean to make a sixteen-element array? Did you mean to create an array filled with the value 0x1? The correct fix here depends on the answer to that question.
Try:
unsigned short result = pec15(dataPtr, 1);
otherwise lengt is 16 (has default value). I'd also advice to remove default value of lengt, as it makes little sense in context of pec15 function.
I want to convert the integer (whose maximum value can reach to 99999999) in to BCD and store in to array of 4 characters.
Like for example:
Input is : 12345 (Integer)
Output should be = "00012345" in BCD which is stored in to array of 4 characters.
Here 0x00 0x01 0x23 0x45 stored in BCD format.
I tried in the below manner but didnt work
int decNum = 12345;
long aux;
aux = (long)decNum;
cout<<" aux = "<<aux<<endl;
char* str = (char*)& aux;
char output[4];
int len = 0;
int i = 3;
while (len < 8)
{
cout <<"str: " << len << " " << (int)str[len] << endl;
unsigned char temp = str[len]%10;
len++;
cout <<"str: " << len << " " << (int)str[len] << endl;
output[i] = ((str[len]) << 4) | temp;
i--;
len++;
}
Any help will be appreciated
str points actually to a long (probably 4 bytes), but the iteration accesses 8 bytes.
The operation str[len]%10 looks as if you are expecting digits, but there is only binary data. In addition I suspect that i gets negative.
First, don't use C-style casts (like (long)a or (char*)). They are a bad smell. Instead, learn and use C++ style casts (like static_cast<long>(a)), because they point out where you are doing things that are dangeruos, instead of just silently working and causing undefined behavior.
char* str = (char*)& aux; gives you a pointer to the bytes of aux -- it is actually char* str = reinterpret_cast<char*>(&aux);. It does not give you a traditional string with digits in it. sizeof(char) is 1, sizeof(long) is almost certainly 4, so there are only 4 valid bytes in your aux variable. You proceed to try to read 8 of them.
I doubt this is doing what you want it to do. If you want to print out a number into a string, you will have to run actual code, not just reinterpret bits in memory.
std::string s; std::stringstream ss; ss << aux; ss >> s; will create a std::string with the base-10 digits of aux in it.
Then you can look at the characters in s to build your BCD.
This is far from the fastest method, but it at least is close to your original approach.
First of all sorry about the C code, I was deceived since this started as a C questions, porting to C++ should not really be such a big deal.
If you really want it to be in a char array I'll do something like following code, I find useful to still leave the result in a little endian format so I can just cast it to an int for printing out, however that is not strictly necessary:
#include <stdio.h>
typedef struct
{
char value[4];
} BCD_Number;
BCD_Number bin2bcd(int bin_number);
int main(int args, char **argv)
{
BCD_Number bcd_result;
bcd_result = bin2bcd(12345678);
/* Assuming an int is 4 bytes */
printf("result=0x%08x\n", *((int *)bcd_result.value));
}
BCD_Number bin2bcd(int bin_number)
{
BCD_Number bcd_number;
for(int i = 0; i < sizeof(bcd_number.value); i++)
{
bcd_number.value[i] = bin_number % 10;
bin_number /= 10;
bcd_number.value[i] |= bin_number % 10 << 4;
bin_number /= 10;
}
return bcd_number;
}