Why does this char array need to be static? - c++

const char * u8_to_bstr(const uint8_t & u8) {
static char s[9]; // space for 8-char string
s[8] = 0; // terminate string
char * sp = s;
for (uint8_t xbit = 0b10000000; xbit > 0; xbit >>= 1) {
cout << s << endl;
*(sp++) = ((u8 & xbit) == xbit) ? '1' : '0';
}
return s;
}
I encountered this piece of code studying that converts a uint8 to a string representing its binary. My question is, why do we need the static qualifier for static char s[9]? When I remove the static qualifier I get some very strange behavior but I don't understand why.

The function returns s, which is declared on the stack of this function. Were it not static, it would go out of scope, effectively disappear, once the function returns because all the storage on the stack is made available for reuse once a function returns. By making it static, it’s forced to have a persistent address in memory. However, it’s still bad design - if you call this function from multiple threads, they’ll fight with each other for use of the static memory space.

To expand on what #VorpalSword offered in their answer, it doesn't have to be static. Instead you could dynamically allocate the array. This dynamically allocated memory will remain valid after u8_to_bstr exits.
const char * u8_to_bstr(const uint8_t & u8) {
const char *s = new char[9]; // space for 8-char string
s[8] = 0; // terminate string
char *sp = s;
for (uint8_t xbit = 0b10000000; xbit > 0; xbit >>= 1) {
cout << s << endl;
*(sp++) = ((u8 & xbit) == xbit) ? '1' : '0';
}
return s;
}
It's a remarkably small change to your code, but it does have implications for how your program works, and you do have to remember later to free up this memory.
delete[] variable_holding_results_of_u8_to_bstr;
This is a simple view os storing your data in memory so that it will remain usable after u8_to_bstr finishes its work without using static. It is by no means the only way or the best way.
In good practice, you'd make use of std::unique_ptr and std::vector rather than manually allocating and deleting arrays. Here is a quick view of your code translated to use these tools. Please note I've added a print_vec helper function.
#include <iostream>
#include <vector>
#include <memory>
using std::vector;
using std::unique_ptr;
using std::make_unique;
void print_vec(unique_ptr<vector<char>> const& v);
unique_ptr<vector<char>> u8_to_bstr(const uint8_t & u8);
int main() {
auto r = u8_to_bstr(45);
print_vec(r);
}
void print_vec(unique_ptr<vector<char>> const& v) {
for (auto ch : *v) {
std::cout << ch;
}
std::cout << std::endl;
}
unique_ptr<vector<char>> u8_to_bstr(const uint8_t & u8) {
auto s = make_unique<vector<char>>(9, '\0');
auto sp = s->begin();
for (uint8_t xbit = 0b10000000; xbit > 0; xbit >>= 1) {
print_vec(s);
*(sp++) = ((u8 & xbit) == xbit) ? '1' : '0';
}
return s;
}
You will almost certainly need to compile this specifying the C++14 or C++17 standards. If you wish to research the types and functions introduced, cppreference.com is a good site, and will tell you what C++ standards types/fucntions were introduced in.

Related

Debug Assertion Failed error when accessing function in DLL

I'm currently learning how to create a C++ library to be referenced in other projects, and I am running into an issue with a "Debug Assertion Failed" error: is_block_type_valid(header-> _block_use). I followed the walkthrough shown here: Create and use your own Dynamic Link Library. Oddly, I am getting the expected answer if I just ignore the error.
My DLL currently only has one function:
cpp:
int calculate_crc(std::string msg)
{
std::vector<std::string> msg_vector = [](std::string& msg1) {
std::string next;
std::vector<std::string> result;
// for each char in string
for (std::string::const_iterator it = msg1.begin(); it != msg1.end(); it++)
{
// if we hit a terminal char
if (*it == ' ')
{
if (!next.empty())
{
// add them to the result vector
result.push_back(next);
next.clear();
}
}
else
{
next += *it;
}
}
if (!next.empty())
{
result.push_back(next);
}
return result;
} (msg);
int crcReg = 0xFFFF;
// iterate through each element in msgVector
for (auto&& element : msg_vector)
{
// step 2: xor operation performed on byte of msg and CRC register
crcReg ^= [](std::string hex) {
std::map<char, int> map;
map['0'] = 0;
map['1'] = 1;
map['2'] = 2;
map['3'] = 3;
map['4'] = 4;
map['5'] = 5;
map['6'] = 6;
map['7'] = 7;
map['8'] = 8;
map['9'] = 9;
map['a'] = 10;
map['b'] = 11;
map['c'] = 12;
map['d'] = 13;
map['e'] = 14;
map['f'] = 15;
return map[hex[1]] + (map[hex[0]] * 16);
} (element);
// step 3-5 are repeated until 8 bit shifts
for (int i = 0; i < 8; i++)
{
int crcCopy = crcReg;
crcReg >>= 1;
if ((crcCopy & 1) == 0)
continue;
else
crcReg ^= 0xA001;
}
}
return crcReg;
}
h:
#pragma once
#ifdef OMRONLIBRARY_EXPORTS
#define OMRONLIBRARY_API __declspec(dllexport)
#else
#define OMRONLIBRARY_API __declspec(dllimport)
#endif
#include <iostream>
extern "C" OMRONLIBRARY_API int calculate_crc(const std::string msg);
std::string is not a safe type to use in a DLL function parameter. Non-POD types should never be passed over a DLL boundary, unless they are type-erased (such as by using a void* pointer) and are only ever accessed directly by code on one side of the boundary and not the other side.
Assuming the caller is even using C++ at all (C-style DLLs can be used in non-C/C++ languages), it may be using a different std::string implementation. Or it may be using a different C++ compiler, or a different version of the same C++ compiler, or even just different settings for alignment, optimizations, etc. And even if all of that matches the DLL, it will likely be using a different instance of the memory manager that the DLL uses for its std::string implementation.
If you want to pass a string to a DLL function safely, use a C-style char* string instead. You can use std::string inside the DLL, if you want to, eg:
int calculate_crc(const char* msg)
{
use msg as-is ...
or
std::string s_msg = msg;
use s_msg as needed ...
}
extern "C" OMRONLIBRARY_API int calculate_crc(const char* msg);

How to calculate the length of a mpz_class in bytes?

I want to implement RSA with padding but first I have to find out the length in bytes of the message which is a mpz_class item. Which function would be useful in cpp to accomplish this?
const mpz_class m(argv[1])
What is the length of m in bytes?
Thank you!
#Shawn's comment is correct: The bytes occupied in memory by your class are not what you should be concerned about. Not only does the location of the bytes in memory depend on how your compiler decides to pack them, but their order can also depend on the hardware used.
So, instead of doing some awkward and very fragile memcopy'ish thing that are almost guaranteed to break at some point, you should construct the message yourself (google keyword: Serialization). This also has the advantage that your class can contain stuff that you don't want to add to the message (caches with temp results, or other implementation/optimization stuff).
To the best of my knowledge C++ (unlike f.ex. C#) does not come with build in serialization support, but there are likely to exist libraries that can do a lot of it for you. Otherwise you just have to write your "data member to byte array" functions yourself.
Super simple example:
#include <vector>
#include<iostream>
class myClass
{
int32_t a;
public:
myClass(int32_t val) : a(val) {}
// Deserializer
bool initFromBytes(std::vector<uint8_t> msg)
{
if (msg.size() < 4)
return false;
a = 0;
for (int i = 0; i < 4; ++i)
{
a += msg[i] << (i * 8);
}
return true;
}
// Serializer
std::vector<uint8_t> toBytes()
{
std::vector<uint8_t> res;
for (int i = 0; i < 4; ++i)
{
res.push_back(a >> (i*8));
}
return res;
}
void print() { std::cout << "myClass: " << a << std::endl; }
};
int main()
{
myClass myC(123456789);
myC.print();
std::vector<uint8_t> message = myC.toBytes();
myClass recreate(0);
if (recreate.initFromBytes(message))
recreate.print();
else
std::cout << "Error" << std::endl;
return 0;
}

Error reserving memory in the heap c++

#include<iostream>
using namespace std;
#include<cstring>
struct stringy
{
char * str;
int ct;
};
void set(stringy & stringa, char ar[]);
void show(stringy & stringa);
int main()
{
stringy beany;
char testing[] = "Reality isn't what is used to be.";
set(beany, testing);
show(beany);
return 0;
}
void set(stringy & stringa, char * ar)
{
char * ps = new char[strlen(ar) + 1];
stringa.str = ps;
strcpy(ar,ps);
cout << strlen(stringa.str);
stringa.ct++;
delete [] ps;
}
void show(stringy & stringa)
{
for(int i = 0; stringa.str[i] != '\0'; i++)
{
cout << stringa.str[i];
}
}
This is my code. It's part of an exercise. I was given the body of the main function as asked to write functions that did the requested task.
locates space to hold copy of testing,
sets str member of beany to point to the
new block, copies testing to new block,
and sets ct member of beany
My issue is with the set function. I feel as though i have satisfied the criteria, the strlen is there because i am trying to figure out what is going on... it returns 0. then the program exits.
There are a lot of problems with this code, among which:
strcpy(ar, ps);
This copies ps to ar, not the other way around. You want:
strcpy(ps, ar);
This error would have been detected by the compiler if the const qualifier were used as it should have been.
Additionally, the delete[] ps at the end of set() should not be there.
Finally, I'm not sure what the purpose of the ct field is, so I can't tell you what it should be, but incrementing an uninitialized field is certainly wrong.

Efficient way to convert int to string

I'm creating a game in which I have a main loop. During one cycle of this loop, I have to convert int value to string about ~50-100 times. So far I've been using this function:
std::string Util::intToString(int val)
{
std::ostringstream s;
s << val;
return s.str();
}
But it doesn't seem to be quite efficient as I've encountered FPS drop from ~120 (without using this function) to ~95 (while using it).
Is there any other way to convert int to string that would be much more efficient than my function?
It's 1-72 range. I don't have to deal with negatives.
Pre-create an array/vector of 73 string objects, and use an index to get your string. Returning a const reference will let you save on allocations/deallocations, too:
// Initialize smallNumbers to strings "0", "1", "2", ...
static vector<string> smallNumbers;
const string& smallIntToString(unsigned int val) {
return smallNumbers[val < smallNumbers.size() ? val : 0];
}
The standard std::to_string function might be a useful.
However, in this case I'm wondering if maybe it's not the copying of the string when returning it might be as big a bottleneck? If so you could pass the destination string as a reference argument to the function instead. However, if you have std::to_string then the compiler probably is C++11 compatible and can use move semantics instead of copying.
Yep — fall back on functions from C, as explored in this previous answer:
namespace boost {
template<>
inline std::string lexical_cast(const int& arg)
{
char buffer[65]; // large enough for arg < 2^200
ltoa( arg, buffer, 10 );
return std::string( buffer ); // RVO will take place here
}
}//namespace boost
In theory, this new specialisation will take effect throughout the rest of the Translation Unit in which you defined it. ltoa is much faster (despite being non-standard) than constructing and using a stringstream.
However, I've experienced problems with name conflicts between instantiations of this specialisation, and instantiations of the original function template, between competing shared libraries.
In order to get around that, I actually just give this function a whole new name entirely:
template <typename T>
inline std::string fast_lexical_cast(const T& arg)
{
return boost::lexical_cast<std::string>(arg);
}
template <>
inline std::string my_fast_lexical_cast(const int& arg)
{
char buffer[65];
if (!ltoa(arg, buffer, 10)) {
boost::throw_exception(boost::bad_lexical_cast(
typeid(std::string), typeid(int)
));
}
return std::string(buffer);
}
Usage: std::string myString = fast_lexical_cast<std::string>(42);
Disclaimer: this modification is reverse-engineered from Kirill's original SO code, not the version that I created and put into production from my company codebase. I can't think right now, though, of any other significant modifications that I made to it.
Something like this:
const int size = 12;
char buf[size+1];
buf[size] = 0;
int index = size;
bool neg = false
if (val < 0) { // Obviously don't need this if val is always positive.
neg = true;
val = -val;
}
do
{
buf[--index] = (val % 10) + '0';
val /= 10;
} while(val);
if (neg)
{
buf[--index] = '-';
}
return std::string(&buf[index]);
I use this:
void append_uint_to_str(string & s, unsigned int i)
{
if(i > 9)
append_uint_to_str(s, i / 10);
s += '0' + i % 10;
}
If You want negative insert:
if(i < 0)
{
s += '-';
i = -i;
}
at the beginning of function.

Adding a string or char array to a byte vector

I'm currently working on a class to create and read out packets send through the network, so far I have it working with 16bit and 8bit integers (Well unsigned but still).
Now the problem is I've tried numerous ways of copying it over but somehow the _buffer got mangled, it segfaulted, or the result was wrong.
I'd appreciate if someone could show me a working example.
My current code can be seen below.
Thanks, Xeross
Main
#include <iostream>
#include <stdio.h>
#include "Packet.h"
using namespace std;
int main(int argc, char** argv)
{
cout << "#################################" << endl;
cout << "# Internal Use Only #" << endl;
cout << "# Codename PACKETSTORM #" << endl;
cout << "#################################" << endl;
cout << endl;
Packet packet = Packet();
packet.SetOpcode(0x1f4d);
cout << "Current opcode is: " << packet.GetOpcode() << endl << endl;
packet.add(uint8_t(5))
.add(uint16_t(4000))
.add(uint8_t(5));
for(uint8_t i=0; i<10;i++)
printf("Byte %u = %x\n", i, packet._buffer[i]);
printf("\nReading them out: \n1 = %u\n2 = %u\n3 = %u\n4 = %s",
packet.readUint8(),
packet.readUint16(),
packet.readUint8());
return 0;
}
Packet.h
#ifndef _PACKET_H_
#define _PACKET_H_
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
using namespace std;
class Packet
{
public:
Packet() : m_opcode(0), _buffer(0), _wpos(0), _rpos(0) {}
Packet(uint16_t opcode) : m_opcode(opcode), _buffer(0), _wpos(0), _rpos(0) {}
uint16_t GetOpcode() { return m_opcode; }
void SetOpcode(uint16_t opcode) { m_opcode = opcode; }
Packet& add(uint8_t value)
{
if(_buffer.size() < _wpos + 1)
_buffer.resize(_wpos + 1);
memcpy(&_buffer[_wpos], &value, 1);
_wpos += 1;
return *this;
}
Packet& add(uint16_t value)
{
if(_buffer.size() < _wpos + 2)
_buffer.resize(_wpos + 2);
memcpy(&_buffer[_wpos], &value, 2);
_wpos += 2;
return *this;
}
uint8_t readUint8()
{
uint8_t result = _buffer[_rpos];
_rpos += sizeof(uint8_t);
return result;
}
uint16_t readUint16()
{
uint16_t result;
memcpy(&result, &_buffer[_rpos], sizeof(uint16_t));
_rpos += sizeof(uint16_t);
return result;
}
uint16_t m_opcode;
std::vector<uint8_t> _buffer;
protected:
size_t _wpos; // Write position
size_t _rpos; // Read position
};
#endif // _PACKET_H_
Since you're using an std::vector for your buffer, you may as well let it keep track of the write position itself and avoid having to keep manually resizing it. You can also avoid writing multiple overloads of the add function by using a function template:
template <class T>
Packet& add(T value) {
std::copy((uint8_t*) &value, ((uint8_t*) &value) + sizeof(T), std::back_inserter(_buffer));
return *this;
}
Now you can write any POD type to your buffer.
implicitly:
int i = 5;
o.write(i);
or explictly:
o.write<int>(5);
To read from the buffer, you will need to keep track of a read position:
template <class T>
T read() {
T result;
uint8_t *p = &_buffer[_rpos];
std::copy(p, p + sizeof(T), (uint8_t*) &result);
_rpos += sizeof(T);
return result;
}
You will need to explicitly pass a type parameter to read. i.e.
int i = o.read<int>();
Caveat: I have used this pattern often, but since I am typing this off the top of my head, there may be a few errors in the code.
Edit: I just noticed that you want to be able to add strings or other non-POD types to your buffer. You can do that via template specialization:
template <>
Packet& add(std::string s) {
add(string.length());
for (size_t i = 0; i < string.length(); ++i)
add(string[i]);
return *this;
}
This tells the compiler: if add is called with a string type, use this function instead of the generic add() function.
and to read a string:
template <>
std::string read<>() {
size_t len = read<size_t>();
std::string s;
while (len--)
s += read<char>();
return s;
}
You could use std::string as internal buffer and use append() when adding new elements.
Thus adding strings or const char* would be trivial.
Adding/writing uint8 can be done with casting it to char, writing uint16 - to char* with length sizeof(uint16_t).
void write_uint16( uint16_t val )
{
m_strBuffer.append( (char*)(&var), sizeof(val) );
}
Reading uint16:
uint16_t read_int16()
{
return ( *(uint16_t*)(m_strBuffer.c_str() + m_nOffset) );
}
You appear to be attempting to print ten bytes out of the buffer when you've only added four, and thus you're running off the end of the vector. This could be causing your seg fault.
Also your printf is trying to print a character as an unsigned int with %x. You need to use static_cast<unsigned>(packet._buffer[i]) as the parameter.
Stylistically:
Packet packet = Packet(); could potentially result in two objects being constructed. Just use Packet packet;
Generally try to avoid protected attributes (protected methods are fine) as they reduce encapsulation of your class.