I've got a buffer of type char*, and a string. I want to place inside the buffer the string length + the string.
I wrote the following code to accomplish this but it doesn't work, because the std::cout<<strlen(buffer) prints "1" no matter what string I pass as parameter of the function.
int VariableLengthRecord :: pack (const std::string strToPack)
{
int strToPackSize = strToPack.length();
if (sizeof(strToPackSize) + strToPackSize > maxBytes - nextByte)
return RES_RECORD_TOO_LONG; // The string is too long
int start = nextByte;
// Copy the string length into the buffer
copyIntToBuffer((buffer+start),strToPackSize);
// Copy the string into the buffer
strcpy((buffer+start+sizeof(strToPackSize)),strToPack.c_str());
// Move the buffer pointer
nextByte += sizeof(strToPackSize) + strToPackSize;
// Update buffer size
bufferSize = nextByte;
std::cout << "Size of buffer = " << strlen(buffer) << std::endl;
return RES_OK;
}
void copyIntToBuffer (char* buffer, int integer)
{
buffer[0] = integer & 0xff;
buffer[1] = (integer >> 8) & 0xff;
buffer[2] = (integer >> 16) & 0xff;
buffer[3] = (integer >> 24) & 0xff;
}
strlen doesn't work on binary data (the length field is binary). Keep track of the real length, or use 5 + strlen(buffer+4) to measure only the text part.
Or, take advantage of the fact that you stored the length inside the buffer, and read the length from there.
strlen is going to walk the string until a null byte (\0) is found. You are attempting to put together a pascal string. If you want to use the built in strlen, you will need to advance the pointer sizeof(string_length_type)
In your case, you can't use cout to directly print the buffer, and you can't use strlen either. The problem is that you are storing binary data.
The strlen function will stop at the first 0x00 byte found in the buffer.
The cout will print garbage for non-printable values.
You will need to convert the buffer to an ASCII version of hex values before printing them.
Something like:
for (i = 0; i < BUFFER_SIZE; i ++)
{
cout << hex << buffer[i];
}
cout << endl;
Related
First of all, forgive my extremely amateur coding knowledge.
I am intern at a company and have been assigned to create a code in C++ that swaps bytes in order to get the correct checksum value.
I am reading a list that resembles something like:
S315FFF200207F7FFFFF42A000000000001B000000647C
S315FFF2003041A00000FF7FFFFF0000001B00000064ED
S315FFF2004042480000FF7FFFFF0000001E000000464F
I have made the program convert this string to hex and then int so that it can be read correctly. I am not reading the first 12 chars or last 2 chars of each line.
My question is how do I make the converted int do a byte swap (little endian to big endian) so that it is readable to the computer?
Again I'm sorry if this is a terrible explanation.
EDIT: I need to essentially take each byte (4 letters) and flip them. i.e: 64C7 flipped to C764, etc etc etc. How would I do this and put it into a new array? Each line is a string right now...
EDIT2: This is part of my code as of now...
int j = 12;
for (i = 0; i < hexLength2 - 5; i++){
string convert1 = ODL.substr(j, 4);
short input_int = stoi(convert1);
short lowBit = 0x00FF & input_int;
short hiBit = 0xFF00 & input_int;
short byteSwap = (lowBit << 8) | (hiBit >> 8);
I think I may need to convert my STOI to a short in some way..
EDIT3: Using the answer code below I get the following...
HEX: 8D --> stored to memory (myMem = unsigned short) as 141 (decimal) -->when byte swapped: -29440
Whats wrong here??
for (i = 0; i < hexLength2 - 5; i++){
string convert1 = ODL.substr(j, 2);
stringstream str1;
str1 << convert1;
str1 >> hex >> myMem[k];
short input_int = myMem[k]; //byte swap
short lowBit = 0x00FF & input_int;
short hiBit = 0xFF00 & input_int;
short byteSwap = (lowBit << 8) | (hiBit >> 8);
cout << input_int << endl << "BYTE SWAP: " <<byteSwap <<"Byte Swap End" << endl;
k++;
j += 2;
You can always do it bitwise too. (Assuming 16-bit word) For example, if you're byte swapping an int:
short input_int = 123; // each of the ints that you have
short input_lower_half = 0x00FF & input_int;
short input_upper_half = 0xFF00 & input_int;
// size of short is 16-bits, so shift the bits halfway in each direction that they were originally
short byte_swapped_int = (input_lower_half << 8) | (input_upper_half >> 8)
EDIT: My exact attempt at using your code
unsigned short myMem[20];
int k = 0;
string ODL = "S315FFF2000000008DC7000036B400003030303030319A";
int j = 12;
for(int i = 0; i < (ODL.length()-12)/4; i++) { // not exactly sure what your loop condition was
string convert1 = ODL.substr(j, 4);
cout << "substring is: " << convert1 << endl;
stringstream str1;
str1 << convert1;
str1 >> hex >> myMem[k];
short input_int = myMem[k]; //byte swap
unsigned short lowBit = 0x00FF & input_int; // changed this to unsigned
unsigned short hiBit = 0xFF00 & input_int; // changed this to unsigned
short byteSwap = (lowBit << 8) | (hiBit >> 8);
cout << hex << input_int << " BYTE SWAPed as: " << byteSwap <<", Byte Swap End" << endl;
k++;
j += 4;
}
it only matters to change the loBit and hiBit to be unsigned since those are the temporary values we're using.
If you're asking what I think you're asking-
First, you need to make sure you know what size your integers are. 32 bits is nice and standard, but check and make sure.
Second, cast your integer array as a char array. Now you can access and manipulate the array one byte at a time.
Third- just reverse the order of every four bytes (after your first 12 char offset). Swap the first and fourth and the second and third.
As the title said, I'm curious if there is a way to read a C++ string with scanf.
I know that I can read each char and insert it in the deserved string, but I'd want something like:
string a;
scanf("%SOMETHING", &a);
gets() also doesn't work.
Thanks in advance!
this can work
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.
scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:
Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.
Of course, I would just use if (std::cin >> str) { ... } but that's a different question.
Problem explained:
You CAN populate the underlying buffer of an std::string using scanf, but(!) the managed std::string object will NOT be aware of the change.
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
So, what happened here?
The object std::string is not aware of changes not performed through the exported, official, API.
When we write to the object through the underlying buffer, the data changes, but the string object is not aware of that.
If we were to replace the original call: token.reseve(64) with token.resize(64), a call that changes the size of the managed string, the results would've been different:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Once again, the result is sub-optimal. The output is correct, but the size isn't.
Solution:
If you really want to make do this, follow these steps:
Call resize to make sure your buffer is big enough. Use a #define for the maximal length (see step 2 to understand why):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Use scanf while limiting the size of the scanned string using "width modifiers" and check the return value (return value is the number of tokens scanned):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Reset the managed string size to the actual size in a safe manner:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
The below snippet works
string s(100, '\0');
scanf("%s", s.c_str());
Here a version without limit of length (in case of the length of the input is unknown).
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
For performance consideration, getchar is definitely faster than scanf, and std::string::reserve could pre-allocate buffers to prevent frequent reallocation.
You can construct an std::string of an appropriate size and read into its underlying character storage:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
The call to str.resize() is critical, otherwise the length of the std::string object will not be updated. Thanks to Daniel Trugman for pointing this out.
(There is no off-by-one error with the size reserved for the string versus the width passed to scanf, because since C++11 it is guaranteed that the character data of std::string is followed by a null terminator so there is room for size+1 characters.)
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string
#define ECHOMAX 100
struct tDataPacket
{
int iPacket_number;
char sData[ECHOMAX];
};
int main () {
tDataPacket packet;
packet.iPacket_number=10;
strcpy(packet.sData,"Hello world");
char buffer[sizeof(tDataPacket)];
memcpy(buffer,&packet.iPacket_number,sizeof(int));
memcpy(buffer+sizeof(int),packet.sData,ECHOMAX);
std::cout<<"Buffer = "<<buffer<<"END";
return 0;
}
In the above code I am trying to pack my structure in a char[] buffer so that I can send it to a UDP socket. But the output of the program is "" string. So nothing is getting copied to 'buffer'. Am I missing anything??
When you copy the int, at least one of the first "n" characters of the buffer will be zero (where "n" is the size of an int on your platform). For example for a 4-byte int:
x00 x00 x00 x0a or x0a x00 x00 x00
Depending on the endianness of your processor.
Printing out the zero will have the effect of terminating the output string.
You have no code to sensibly print the contents of the buffer, so you are expecting this to work by magic. The stream's operator << function expects a pointer to a C-style string, which the buffer isn't.
It's "" because int iPacket_number is probably laid out in memory as:
0x00 0x00 0x00 0x0a
which is an empty string (nul-terminator in the first character).
Firstly you probably want some sort of marshalling so that the on-the-wire representation is well established and portable (think endian differences between platforms).
Secondly you shouldn't need to "print" the resulting string; it makes no sense.
Thirdly you want unsigned char, not (signed) char.
You can't print an integer as text, because it's not text.
You will need to do a loop (or something like that) to print the actual contents of the buffer:
std::cout << "Buffer=";
for(size_t i = 0; i < sizeof(tDataPacket); i++)
{
std::cout << hex << (unsigned int)buffer[i] << " ";
if ((i & 0xf) == 0xf) std::cout << endl; // Newline every 16.
}
std::cout << "END" << endl;
You can do this but it's not really relevant to display binary data like that:
std::cout<<"Buffer = "; for each (auto c in buffer)
{
std::cout<< c;
}
std::cout <<"END";
Basically what I want to do is to read a binary file, and extract 4 consecutive values at address e.g. 0x8000. For example, the 4 numbers are 89 ab cd ef. I want to read these values and store them into a buffer, and then convert the buffer to int type. I have tried the following method:
ifstream *pF = new ifstream();
buffer = new char[4];
memset(buffer, 0, 4);
pF->read(buffer, 4);
When I tried
cout << buffer << endl;
nothing happens, I guarantee that there are values at this location (I can view the binary file in hex viewer). Could anyone show me the method to convert the buffer to int type and properly display it? Thank you.
Update
int number = buffer[0];
for (int i = 0; i < 4; ++i)
{
number <<= 8;
number |= buffer[i];
}
It also depends on Little endian and Bit endian notations. If you compose your number with another way, you can use number |= buffer[3 - i]
And in order to display hex int you can use
#include <iomanip>
cout << hex << number;
cout << hex << buffer[0] << buffer[1] << buffer[2] << buffer[3] << endl;
See http://www.cplusplus.com/reference/iostream/manipulators/hex/
As part of an assignment, I need to read data from a binary file which consists of int, char datatypes of data. This binary file is divided into records 96 bytes each. I am trying to reading these 96 bytes into a char buffer and then trying to split them according to info I have. But I am getting nothing when trying to get int values from the buffer. Can you help me in this?
#include<iostream>
#include<fstream>
#include<cstdio>
using namespace std;
int main()
{
char buffer[100];
char *p;
char temp[10];
int val;
fstream ifs,ofs;
ifs.open("write.bin",ios::binary);
if(ifs.read(buffer,96))
{
cout << "READ" << endl;
}
p = buffer;
memcpy(temp,buffer,4);
cout << temp << endl;
val = atoi(temp);
cout << val << endl;
}
I used strncpy also in place of memcpy.
The output is 0 for val and blank for temp.
atoi transforms strings (char arrays) into integers. So something like "42" would return the integer 42. The way your question is written, it sounds like the integers are simply stored as binary in the textfile.
A simple cast of the buffer pointer to the desired type plus a dereference should do:
/* read 96 bytes into char array buffer */
uint32_t your_number = *(uint32_t*)buffer;
cout << your_number << endl;
If you want to use memcpy, there's no need to copy to a char array, you can copy directly to an integer address:
uint32_t your_number;
memcpy(&your_number, buffer, 4);
cout << your_number << endl;
With plain C (not C++) this would be:
uint32_t your_number;
FILE *f = fopen("write.bin", "r");
fread(&your_number, sizeof(uint32_t), 1, f); /* uint32's size is 4 bytes */
fclose(f);
printf("%d\n", your_number);
I chose uint32_t as a data type, because it is guaranteed to have 32 bits/4 bytes – int might, on some platforms/compilers, be of different size.
Unlike C-style functions, read does not return number or bytes read, instead, it returns istream&. So to check the result, call ifs.gcount() after ifs.read().