int x = 1231212;
memcpy(pDVal, &x, 4);
int iDSize = sizeof(double);
int i = 0;
for (; i<iDSize; i++)
{
char c;
memcpy(&c, &(pDVal[i]), 1);
printf("%d|\n", c);
printf("%x|\n", c);
}
I used above code segment to print the hex value of each byte of a Integer. But that is not working properly. What is issue here ?
Try something like this:
void Int32ToUInt8Arr( int32 val, uint8 *pBytes )
{
pBytes[0] = (uint8)val;
pBytes[1] = (uint8)(val >> 8);
pBytes[2] = (uint8)(val >> 16);
pBytes[3] = (uint8)(val >> 24);
}
or perhaps:
UInt32 arg = 18;
array<Byte>^byteArray = BitConverter::GetBytes( arg);
// {0x12, 0x00, 0x00, 0x00 }
byteArray->Reverse(byteArray);
// { 0x00, 0x00, 0x00, 0x12 }
for the second example see: http://msdn2.microsoft.com/en-us/library/de8fssa4(VS.80).aspx
Hope this helps.
Just use the sprintf function. You will get a char*, so you have your array.
See the example on the webpage
Your code looks awful. That's it.
memcpy(pDVal, &x, 4);
What is pDVal? Why do you use 4? Is it sizeof(int)?
int iDSize = sizeof(double);
Why sizeof(double)? May be you need sizeof(int).
memcpy(&c, &(pDVal[i]), 1); makes copy first byte of i-th array pDVal element.
printf("%d|\n", c); is not working because "%d" is waiting integer.
Print like this:
printf("%d|\n", c & 0xff);
printf("%x|\n", c & 0xff);
If you are serious about the c++, this is how I would suggest to do it.
#include <sstream>
template <typename Int>
std::string intToStr(Int const i) {
std::stringstream stream;
stream << std::hex << i;
return stream.str();
}
Which you may invoke as intToStr(1231212). If you insist on getting a char array (I strongly suggest you use std::string), you can copy the c_str() result over:
std::string const str = intToStr(1231212);
char* const chrs = new char[str.length()+1];
strcpy(chrs,str.c_str()); // needs <string.h>
Related
I am trying to convert some C++ code to C for my compiler that can't run with C++ code. I'd like to create the template below to C. This template converts the decimal integer to hexadecimal, and adds 0 in front of value if the size of the hexadecimal string is smaller than (sizeof(T)*2). Data type T can be unsigned char, char, short, unsigned short, int, unsigned int, long long, and unsigned long long.
template< typename T > std::string hexify(T i)
{
std::stringbuf buf;
std::ostream os(&buf);
os << std::setfill('0') << std::setw(sizeof(T) * 2)
<< std::hex << i;
std::cout<<"sizeof(T) * 2 = "<<sizeof(T) * 2<<" buf.str() = "<<buf.str()<<" buf.str.c_str() = "<<buf.str().c_str()<<std::endl;
return buf.str().c_str();
}
Thank you for tour help.
Edit 1: I have tried to use the declaration
char * hexify (void data, size_t data_size)
but when I call with the int value int_value:
char * result = hexify(int_value, sizeof(int))
it doesn't work because of:
noncompetitive type (void and int).
So in this case, do I have to use a macro? I haven't tried with macro because it's complicated.
C does not have templates. One solution is to pass the maximum width integer supported (uintmax_t, in Value below) and the size of the original integer (in Size). One routine can use the size to determine the number of digits to print. Another complication is C does not provide C++’s std::string with is automatic memory management. A typical way to handle this in C is for the called function to allocate a buffer and return it to the caller, who is responsible for freeing it when done.
The code below shows a hexify function that does this, and it also shows a Hexify macro that takes a single parameter and passes both its size and its value to the hexify function.
Note that, in C, character constants such as 'A' have type int, not char, so some care is needed in providing the desired size. The code below includes an example for that.
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
char *hexify(size_t Size, uintmax_t Value)
{
// Allocate space for "0x", 2*Size digits, and a null character.
size_t BufferSize = 2 + 2*Size + 1;
char *Buffer = malloc(BufferSize);
// Ensure a buffer was allocated.
if (!Buffer)
{
fprintf(stderr,
"Error, unable to allocate buffer of %zu bytes in %s.\n",
BufferSize, __func__);
exit(EXIT_FAILURE);
}
// Format the value as "0x" followed by 2*Size hexadecimal digits.
snprintf(Buffer, BufferSize, "0x%0*" PRIxMAX, (int) (2*Size), Value);
return Buffer;
}
/* Provide a macro that passes both the size and the value of its parameter
to the hexify function.
*/
#define Hexify(x) (hexify(sizeof (x), (x)))
int main(void)
{
char *Buffer;
/* Show two examples of using the hexify function with different integer
types. (The examples assume ASCII.)
*/
char x = 'A';
Buffer = hexify(sizeof x, x);
printf("Character '%c' = %s.\n", x, Buffer); // Prints "0x41".
free(Buffer);
int i = 123;
Buffer = hexify(sizeof i, i);
printf("Integer %d = %s.\n", i, Buffer); // Prints "0x00007b".
free(Buffer);
/* Show examples of using the Hexify macro, demonstrating that 'A' is an
int value, not a char value, so it would need to be cast if a char is
desired.
*/
Buffer = Hexify('A');
printf("Character '%c' = %s.\n", 'A', Buffer); // Prints "0x00000041".
free(Buffer);
Buffer = Hexify((char) 'A');
printf("Character '%c' = %s.\n", 'A', Buffer); // Prints "0x41".
free(Buffer);
}
You don't need templates if you step down to raw bits and bytes.
If performance is important, it is also best to roll out the conversion routine by hand, since the string handling functions in C and C++ come with lots of slow overhead. The somewhat well-optimized version would look something like this:
char* hexify_data (char*restrict dst, const char*restrict src, size_t size)
{
const char NIBBLE_LOOKUP[0xF+1] = "0123456789ABCDEF";
char* d = dst;
for(size_t i=0; i<size; i++)
{
size_t byte = size - i - 1; // assuming little endian
*d = NIBBLE_LOOKUP[ (src[byte]&0xF0u)>>4 ];
d++;
*d = NIBBLE_LOOKUP[ (src[byte]&0x0Fu)>>0 ];
d++;
}
*d = '\0';
return dst;
}
This breaks down any passed type byte-by-byte, using a character type. Which is fine, when using character types specifically. It also uses caller allocation for maximum performance. (It can also be made endianess-independent with an extra check per loop.)
We can make the call a bit more convenient with a wrapper macro:
#define hexify(buf, var) hexify_data(buf, (char*)&var, sizeof(var))
Full example:
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#define hexify(buf, var) hexify_data(buf, (char*)&var, sizeof(var))
char* hexify_data (char*restrict dst, const char*restrict src, size_t size)
{
const char NIBBLE_LOOKUP[0xF+1] = "0123456789ABCDEF";
char* d = dst;
for(size_t i=0; i<size; i++)
{
size_t byte = size - i - 1; // assuming little endian
*d = NIBBLE_LOOKUP[ (src[byte]&0xF0u)>>4 ];
d++;
*d = NIBBLE_LOOKUP[ (src[byte]&0x0Fu)>>0 ];
d++;
}
*d = '\0';
return dst;
}
int main (void)
{
char buf[50];
int32_t i32a = 0xABCD;
puts(hexify(buf, i32a));
int32_t i32b = 0xAAAABBBB;
puts(hexify(buf, i32b));
char c = 5;
puts(hexify(buf, c));
uint8_t u8 = 100;
puts(hexify(buf, u8));
}
Output:
0000ABCD
AAAABBBB
05
64
an optional solution is to use format string like printf
note that you can't return pointer to local variable, but you can get the buffer as argument, (here it is without boundaries check).
char* hexify(char* result, const char* format, void* arg)
{
int size = 0;
if(0 == strcmp(format,"%d") || 0 == strcmp(format,"%u"))
{
size=4;
sprintf(result,"%08x",arg);
}
else if(0 == strcmp(format,"%hd") || 0 == strcmp(format,"%hu"))
{
size=2;
sprintf(result,"%04x",arg);
}
else if(0 == strcmp(format,"%hhd")|| 0 == strcmp(format,"%hhu"))
{
size=1;
sprintf(result,"%02x",arg);
}
else if(0 == strcmp(format,"%lld") || 0 == strcmp(format,"%llu") )
{
size=8;
sprintf(result,"%016x",arg);
}
//printf("size=%d", size);
return result;
}
int main()
{
char result[256];
printf("%s", hexify(result,"%hhu", 1));
return 0;
}
Short Version:
I have a String: 0x4D;0x90;0x69
I want an array
static const uint8_t array[] = {
0x4D, 0x90, 0x69
}
How to do?
Longer Version:
I have an String (buffer) with like this: 0x4D0x900x69 between those hex "numbers" are Zero Width Spaces, and I split those up into a vector of strings using
std::vector<std::string> v{ explode(buffer, '\u200B') };
I want for to have an Vector with uint8_t data in it.
I already tried to reinterpret_cast the string, and that actually worked. But I have put it in a forloop an it should push the result into an uint8_t Vector, but in the Vector were only 0x00 in it.
std::vector < std::string > v {
explode(buffer, '\u200B')
};
std::vector < uint8_t * > ob;
for (auto n: v) {
uint8_t * p = reinterpret_cast < uint8_t * > ( & n);
//std::cout << n << " | " << p << std::endl;
ob.push_back(p);
};
for (auto na : ob) std::cout << na << std::endl;
I only get three 0x00 in the console.
I want to have an static const uint8_t arr[] containing the buffer splited up.
Edit:
I have forgot to add the explodefunction here, its basicly just a split. ```cpp
const std::vector<std::string> explode(const std::string& s, const char& c)
{
std::string buff{ "" };
std::vector<std::string> v;
for (auto n : s)
{
if (n != c) buff += n; else
if (n == c && buff != "") { v.push_back(buff); buff = ""; }
}
if (buff != "") v.push_back(buff);
return v;
}
for (auto n : v)
This takes a copy of each thing in v which lives for the duration of the loop body.
uint8_t * p = reinterpret_cast < uint8_t * > ( & n);
This gives you a pointer to the local copied thing after reinterpretation.
ob.push_back(p);
This stores the pointer into a vector.
}
This makes all those pointers dangling.
To fix this UB, you could try for (const auto& n : v) instead.
However, there are other problems. Each of those "things" is a std::string! It is meaningless to cast a std::string* to uint8_t* and not really clear what you meant to achieve with that. Did you mean to cast the result of n.c_str() to uint8_t*? But then that is not really achieving anything either.
I think you need to look into a better way to interpret a sequence of characters as a number and convert it to an integer.
I the project I have a struct that has one member of type unsigned int array(uint8_t) like below
typedef uint8_t U8;
typedef struct {
/* other members */
U8 Data[8];
} Frame;
a pointer to a variable of type Frame is received that during debug I see it as below in console of VS2017
/* the function signatur */
void converter(Frame* frm){...}
frm->Data 0x20f1feb0 "6þx}\x1òà... unsigned char[8] // in debug console
now I want to assign it to an 8byte string
I did it like below, but it concatenates the numeric values of the array and results in something like "541951901201251242224"
std::string temp;
for (unsigned char i : frm->Data)
{
temp += std::to_string(i);
}
also tried const std::string temp(reinterpret_cast<char*>(frm->Data, 8)); which throws exception
In your original cast const std::string temp(reinterpret_cast<char*>(frm->Data, 8)); you put the closing parenthesis in the wrong place, so that it ends up doing reinterpret_cast<char*>(8) and that is the cause of the crash.
Fix:
std::string temp(reinterpret_cast<char const*>(frm->Data), sizeof frm->Data);
Just leave away the std::to_string. It converts numeric values to their string representation. So even if you give it a char, it will just cast that to an integer and convert it to the numerical representation of that integer instead. On the other hand, just adding a char to an std::string using += works fine. Try this:
int main() {
typedef uint8_t U8;
U8 Data[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F };
std::string temp;
for (unsigned char i : Data)
{
temp += i;
}
std::cout << temp << std::endl;
}
See here for more information and examples on std::string's += operator.
I am copying double value into unsigned char* in the following way.
unsigned char* cmdBody;
double val = (double)-1;
std::ostringstream sstream;
sstream << val;
std::string valString = sstream.str();
unsigned int dataSize = valString.size() + 1;
cmdBody = (unsigned char*)malloc(dataSize);
memset(cmdBody, 0, dataSize);
memcpy(cmdBody, (unsigned char*)valString.c_str(), dataSize - 1);
cmdBody[dataSize - 1] = '\0';
From cmdBody I need to convert the value into double type. How to do it?
C much?
Your solution is very simple if you just use a std::string:
const auto val = -1.0; // Input double
const auto cmdBody = std::to_string(val); // Convert double to a std::string
const auto foo = std::stod(cmdBody); // Convert std::string to a double
It's important to note that there is no need to allocate, memcopy, or null-terminate when constructing a std::string. Which vastly simplifies your code.
Use std::stod, something like this:
#include <string>
double d = std::stod(cmdBody);
std::istringstream istream(std::string("3.14"));
double d;
istream >> d;
if (!istream.fail())
{
// convertion ok
}
I'm reading a string from a file so it's in the form of a char array. I need to tokenize the string and save each char array token as a uint8_t hex value in an array.
char* starting = "001122AABBCC";
// ...
uint8_t[] ending = {0x00,0x11,0x22,0xAA,0xBB,0xCC}
How can I convert from starting to ending? Thanks.
Here is a complete working program. It is based on Rob I's solution, but fixes several problems has been tested to work.
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
const char* starting = "001122AABBCC";
int main()
{
std::string starting_str = starting;
std::vector<unsigned char> ending;
ending.reserve( starting_str.size());
for (int i = 0 ; i < starting_str.length() ; i+=2) {
std::string pair = starting_str.substr( i, 2 );
ending.push_back(::strtol( pair.c_str(), 0, 16 ));
}
for(int i=0; i<ending.size(); ++i) {
printf("0x%X\n", ending[i]);
}
}
strtoul will convert text in any base you choose into bytes. You have to do a little work to chop the input string into individual digits, or you can convert 32 or 64bits at a time.
ps uint8_t[] ending = {0x00,0x11,0x22,0xAA,0xBB,0xCC}
Doesn't mean anything, you aren't storing the data in a uint8 as 'hex', you are storing bytes, it's upto how you (or your debugger) interpretes the binary data
With C++11, you may use std::stoi for that :
std::vector<uint8_t> convert(const std::string& s)
{
if (s.size() % 2 != 0) {
throw std::runtime_error("Bad size argument");
}
std::vector<uint8_t> res;
res.reserve(s.size() / 2);
for (std::size_t i = 0, size = s.size(); i != size; i += 2) {
std::size_t pos = 0;
res.push_back(std::stoi(s.substr(i, 2), &pos, 16));
if (pos != 2) {
throw std::runtime_error("bad character in argument");
}
}
return res;
}
Live example.
I think any canonical answer (w.r.t. the bounty notes) would involve some distinct phases in the solution:
Error checking for valid input
Length check and
Data content check
Element conversion
Output creation
Given the usefulness of such conversions, the solution should probably include some flexibility w.r.t. the types being used and the locale required.
From the outset, given the date of the request for a "more canonical answer" (circa August 2014) liberal use of C++11 will be applied.
An annotated version of the code, with types corresponding to the OP:
std::vector<std::uint8_t> convert(std::string const& src)
{
// error check on the length
if ((src.length() % 2) != 0) {
throw std::invalid_argument("conversion error: input is not even length");
}
auto ishex = [] (decltype(*src.begin()) c) {
return std::isxdigit(c, std::locale()); };
// error check on the data contents
if (!std::all_of(std::begin(src), std::end(src), ishex)) {
throw std::invalid_argument("conversion error: input values are not not all xdigits");
}
// allocate the result, initialised to 0 and size it to the correct length
std::vector<std::uint8_t> result(src.length() / 2, 0);
// run the actual conversion
auto str = src.begin(); // track the location in the string
std::for_each(result.begin(), result.end(), [&str](decltype(*result.begin())& element) {
element = static_cast<std::uint8_t>(std::stoul(std::string(str, str + 2), nullptr, 16));
std::advance(str, 2); // next two elements
});
return result;
}
The template version of the code adds flexibility;
template <typename Int /*= std::uint8_t*/,
typename Char = char,
typename Traits = std::char_traits<Char>,
typename Allocate = std::allocator<Char>,
typename Locale = std::locale>
std::vector<Int> basic_convert(std::basic_string<Char, Traits, Allocate> const& src, Locale locale = Locale())
{
using string_type = std::basic_string<Char, Traits, Allocate>;
auto ishex = [&locale] (decltype(*src.begin()) c) {
return std::isxdigit(c, locale); };
if ((src.length() % 2) != 0) {
throw std::invalid_argument("conversion error: input is not even length");
}
if (!std::all_of(std::begin(src), std::end(src), ishex)) {
throw std::invalid_argument("conversion error: input values are not not all xdigits");
}
std::vector<Int> result(src.length() / 2, 0);
auto str = std::begin(src);
std::for_each(std::begin(result), std::end(result), [&str](decltype(*std::begin(result))& element) {
element = static_cast<Int>(std::stoul(string_type(str, str + 2), nullptr, 16));
std::advance(str, 2);
});
return result;
}
The convert() function can then be based on the basic_convert() as follows:
std::vector<std::uint8_t> convert(std::string const& src)
{
return basic_convert<std::uint8_t>(src, std::locale());
}
Live sample.
uint8_t is typically no more than a typedef of an unsigned char. If you're reading characters from a file, you should be able to read them into an unsigned char array just as easily as a signed char array, and an unsigned char array is a uint8_t array.
I'd try something like this:
std::string starting_str = starting;
uint8_t[] ending = new uint8_t[starting_str.length()/2];
for (int i = 0 ; i < starting_str.length() ; i+=2) {
std::string pair = starting_str.substr( i, i+2 );
ending[i/2] = ::strtol( pair.c_str(), 0, 16 );
}
Didn't test it but it looks good to me...
You may add your own conversion from set of char { '0','1',...'E','F' } to uint8_t:
uint8_t ctoa(char c)
{
if( c >= '0' && c <= '9' ) return c - '0';
else if( c >= 'a' && c <= 'f' ) return 0xA + c - 'a';
else if( c >= 'A' && c <= 'F' ) return 0xA + c - 'A';
else return 0;
}
Then it will be easy to convert a string in to array:
uint32_t endingSize = strlen(starting)/2;
uint8_t* ending = new uint8_t[endingSize];
for( uint32_t i=0; i<endingSize; i++ )
{
ending[i] = ( ctoa( starting[i*2] ) << 4 ) + ctoa( starting[i*2+1] );
}
This simple solution should work for your problem
char* starting = "001122AABBCC";
uint8_t ending[12];
// This algo will work for any size of starting
// However, you have to make sure that the ending have enough space.
int i=0;
while (i<strlen(starting))
{
// convert the character to string
char str[2] = "\0";
str[0] = starting[i];
// convert string to int base 16
ending[i]= (uint8_t)atoi(str,16);
i++;
}
uint8_t* ending = static_cast<uint8_t*>(starting);