I have a unsigned char*. Typically this points to a chunk of data, but in some cases, the pointer IS the data, ie. casting a int value to the unsigned char* pointer (unsigned char* intData = (unsigned char*)myInteger;), and vice versa.
However, I need to do this with a float value, and it keeps giving me conversion errors.
unsigned char* data;
float myFloat = (float)data;
How can I do this?
bit_cast:
template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
static_assert(sizeof(Dest)==sizeof(Source), "size of destination and source objects must be equal");
static_assert(std::is_trivially_copyable<Dest>::value, "destination type must be trivially copyable.");
static_assert(std::is_trivially_copyable<Source>::value, "source type must be trivially copyable");
Dest dest;
std::memcpy(&dest, &source, sizeof(dest));
return dest;
}
Usage:
char *c = nullptr;
float f = bit_cast<float>(c);
c = bit_cast<char *>(f);
The only correct way to use a given variable to store other data is to copy the data byte-wise:
template <typename T>
void store(unsigned char * & p, T const & val)
{
static_assert(sizeof(unsigned char *) >= sizeof(T));
char const * q = reinterpret_cast<char const *>(&val);
std::copy(q, q + sizeof(T), reinterpret_cast<char *>(&p));
}
Usage:
unsigned char * p;
store(p, 1.5);
store(p, 12UL);
The matching retrieval function:
template <typename T>
T load(unsigned char * const & p)
{
static_assert(sizeof(unsigned char *) >= sizeof(T));
T val;
char const * q = reinterpret_cast<char const *>(&p);
std::copy(q, q + sizeof(T), reinterpret_cast<char *>(&val));
return val;
}
Usage:
auto f = load<float>(p);
If your compiler supports it (GCC does) then use a union. This is undefined behavior according to the C++ standard.
union {
unsigned char* p;
float f;
} pun;
pun.p = data;
float myFloat = pun.f;
This works if sizeof(unsigned char *) == sizeof(float). If pointers are larger than floats then you have to rethink your strategy.
See wikipedia article on type punning and in particular the section on use of a union.
GCC allows type punning using a union as long as you use the union directly and not typecasting to a union... see this IBM discussion on type-pun problems for correct and incorrect ways of using GCC for type punning.
Also see wikipedia's article on strong and weak typing and a well researched article on type punning and strict aliasing.
unsigned char* data;
float myFloat = *(float*)data;
Related
In my compile time function I'd like to work with strings. BOTH ANSI and WIDE ones. So, I added a quick template to handle both. This is all easy-peasy, but I've got a special function which calculates security checksum on strings. This works on a byte array and it would take quite huge effort to rewrite to work on variable buffer size, so I thought I will just simply narrow the wchar down to char and let my function work on it. By default it doesn't work as I thought it should be.
Sample code to reproduce my problem:
https://godbolt.org/z/ya2zq7
#include <iostream>
constexpr void hack(const char* const from, const size_t fromLen, char* const to)
{
for (size_t i = 0; i < fromLen; i++)
{
to[i] = from[i] + 1;
}
}
template <typename U, std::size_t LENGTH>
class EncryptedStorage
{
U m_data[LENGTH]{};
public:
constexpr EncryptedStorage(const U* input)
{
hack(static_cast<const char* const>(input), LENGTH * sizeof(U), static_cast<char* const>(m_data));
}
};
int main()
{
// Test with CHAR
constexpr char test[] = "Hello World";
constexpr size_t size = sizeof(test) / sizeof(test[0]);
constexpr auto encrypted = EncryptedStorage<char, size>(test);
// test with WCHAR
constexpr wchar_t wtest[] = L"Hello World";
constexpr size_t wsize = sizeof(wtest) / sizeof(wtest[0]);
constexpr auto wencrypted = EncryptedStorage<wchar_t, wsize>(wtest);
}
If you comment the wide strings it will compile perfectly. Is it possible to do what I want, or I should really really rework all my algorithm to work on variable size?
The basic problem in your code is that you can't use static_cast to covert between pointers to different data types - when those types are unrelated, as char and wchar_t are; for this, you need a reinterpret_cast or a C-style cast:
constexpr EncryptedStorage(const U* input)
{
hack(reinterpret_cast<const char* const>(input), LENGTH * sizeof(U), reinterpret_cast<char* const>(m_data));
}
However, once you have such a cast, your EncyptedStorage function can no longer be evaluated at compile time, so two of theconstexpr declarations in your main will fail, and you will have to just use const instead:
const auto encrypted = EncryptedStorage<char, size>(test);
const auto wencrypted = EncryptedStorage<wchar_t, wsize>(wtest); // Can't use constexpr
EDIT:
Another way (perhaps nicer) is to use function-style casts:
using pcchar = const char* const;
using pchar = char* const;
constexpr EncryptedStorage(const U* input)
{
hack(pcchar(input), LENGTH * sizeof(U), pchar(m_data));
}
With this, you can use constexpr for encrypted but not for wencrypted!
What is the type of T if I write something like that:
template<typename T>
class AClass{
private:
T member;
public:
AClass(const T& value = T()) : member(value) {}
};
int main(){
const char* n = "Hello";
AClass<char*> a(n);
return 0;
}
Does T refers to a char or a pointer over a char?
Thanks for your answers
Facts:
T is char * in your example
The example won't compile
Think about your constructor:
AClass(const T& value = T())
What you want is a pointer to const char, that is const char *.
In your constructor you are saying that T is const, thus you are asking for a const pointer to char, that is char * const.
They are actually two different beasts and the compiler complains about the lack of a const (let me say) in the right place in your constructor. That's because a conversion from const char * to char * is not allowed.
Assuming you meant to write
AClass<char*> a('n');
T is a char* (address), but 'n' would resolve to simply char. I don't believe it would compile.
This is a part of my code ...
As I know the casting is proper as I have done below, but I am getting the linting warning for my logic.. Can You explain it why it is like this ..
Part of my code :
typedef struct
{
char appid[4]; /**< application id */
int32 pid; /**< process id of user application */
} DApplication;
static int32 d_cmp(const void *m1, const void *m2)
{
DApplication *mi1 = (DApplication *) m1; //Line 1
DApplication *mi2 = (DApplication *) m2; //Line 2
return memcmp(mi1->appid, mi2->appid, 4); //Line 3
}
And warnings are :
Sample.cpp (line 1):Note 960: Violates MISRA 2004 Required Rule 11.5, attempt to cast away const/volatile from a pointer or reference
Sample.cpp (line 2):Note 960: Violates MISRA 2004 Required Rule 11.5, attempt to cast away const/volatile from a pointer or reference
Sample.cpp (line 3):Note 960: Violates MISRA 2004 Required Rule 10.1, Implicit conversion changes signedness
...Courtsey MISRA
As per the MISRA rule : Rule 11.5 (required): A cast shall not be performed that removes any const or volatile
qualification from the type addressed by a pointer.
[Undefined 39, 40]
Any attempt to remove the qualification associated with the addressed type by using casting is a
violation of the principle of type qualification. Notice that the qualification referred to here is not
the same as any qualification that may be applied to the pointer itself.
uint16_t x;
uint16_t * const cpi = &x; /* const pointer */
uint16_t * const * pcpi; /* pointer to const pointer */
const uint16_t * * ppci; /* pointer to pointer to const */
uint16_t * * ppi;
const uint16_t * pci; /* pointer to const */
volatile uint16_t * pvi; /* pointer to volatile */
uint16_t * pi;
...
pi = cpi; /* Compliant - no conversion
no cast required */
pi = (uint16_t *)pci; /* Not compliant */
pi = (uint16_t *)pvi; /* Not compliant */
ppi = (uint16_t * *)pcpi; /* Not compliant */
ppi = (uint16_t * *)ppci; /* Not compliant */
SO According to this rule i think it is fine
As I know the casting is proper as I have done below...
Why do you think your casting is "proper"? You have const parameters and you're removing the const-ness from them for no good reason at all. What's the type of memcmp() parameters on your system? They should be const pointers - from http://en.cppreference.com/w/cpp/string/byte/memcmp
int memcmp( const void* lhs, const void* rhs, std::size_t count );
So, you can fix your function like this:
static int32 d_cmp(const void* m1, const void* m2)
{
return memcmp(static_cast<const DApplication*>(m1)->appid,
static_cast<const DApplication*>(m2)->appid,
sizeof DApplication().appid);
}
It is like this because you are playing with fire. You are not using the type system, you are circumventing it. There are much better ways to do this in C++, such as:
static int32 d_cmp(const DApplication *m1, const DApplication *m2)
or
const DApplication *mi1 = static_cast<const DApplication *>(m1);
The problem is that you are casting away the constness. You don't need to do that in anyway if you are just gonna use memcmp since it takes (const void*, const void*, size_t).
Try this:
#include <cstring> // memcmp
typedef struct {
char appid[4]; /**< application id */
int pid; /**< process id of user application */
} DApplication;
static int d_cmp(const void *m1, const void *m2)
{
const DApplication *mi1 = static_cast<const DApplication *>(m1); //Line 1
const DApplication *mi2 = static_cast<const DApplication *>(m2); //Line 2
return memcmp(mi1->appid, mi2->appid, 4); //Line 3
}
int main(void)
{
DApplication a1 = {{0,0,0,0}, 1};
DApplication a2 = {{0,0,0,1}, 1};
return d_cmp(&a1, &a2);
}
Remember to compile it with a c++ compiler (use g++ and not gcc).
As question is tagged C++ here is somewhat more like C++ solution.
This solution, solves problem by eliminating casting, and also makes code cleaner, safer and, probably, faster.
You can use anonymous namespace instead of static.
You can use function template to keep type safety (if you'll need diffrent types at all. If not, just hard-code DApplication).
No need to use pointers. Use references instead.
Use std::array instead of C-style array. It provides operator==() for convenient (and, more likely, faster) element-wise comparison, so no need to memcmp.
struct DApplication
{
std::array <char, 4> appid;
int pid;
};
struct NotDApplication
{
int foo;
};
namespace {
template <typename T>
bool CompareAppIds(const T& mi1, const T& mi2)
{
return (mi1.appid == mi2.appid);
}
}
int main()
{
DApplication a, b;
NotDApplication c, d;
bool isEqual = CompareAppIds(a, b); // OK
bool isEqual2 = CompareAppIds(c, d); // Compile error:
// 'appid' : is not a member
// of 'NotDApplication'
}
Also, you can overload operator==() for DApplication if suitable.
I am trying to extract the bits from a float without invoking undefined behavior. Here is my first attempt:
unsigned foo(float x)
{
unsigned* u = (unsigned*)&x;
return *u;
}
As I understand it, this is not guaranteed to work due to strict aliasing rules, right? Does it work if a take an intermediate step with a character pointer?
unsigned bar(float x)
{
char* c = (char*)&x;
unsigned* u = (unsigned*)c;
return *u;
}
Or do I have to extract the individual bytes myself?
unsigned baz(float x)
{
unsigned char* c = (unsigned char*)&x;
return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}
Of course this has the disadvantage of depending on endianness, but I could live with that.
The union hack is definitely undefined behavior, right?
unsigned uni(float x)
{
union { float f; unsigned u; };
f = x;
return u;
}
Just for completeness, here is a reference version of foo. Also undefined behavior, right?
unsigned ref(float x)
{
return (unsigned&)x;
}
So, is it possible to extract the bits from a float (assuming both are 32 bits wide, of course)?
EDIT: And here is the memcpy version as proposed by Goz. Since many compilers do not support static_assert yet, I have replaced static_assert with some template metaprogramming:
template <bool, typename T>
struct requirement;
template <typename T>
struct requirement<true, T>
{
typedef T type;
};
unsigned bits(float x)
{
requirement<sizeof(unsigned)==sizeof(float), unsigned>::type u;
memcpy(&u, &x, sizeof u);
return u;
}
About the only way to truly avoid any issues is to memcpy.
unsigned int FloatToInt( float f )
{
static_assert( sizeof( float ) == sizeof( unsigned int ), "Sizes must match" );
unsigned int ret;
memcpy( &ret, &f, sizeof( float ) );
return ret;
}
Because you are memcpying a fixed amount the compiler will optimise it out.
That said the union method is VERY widely supported.
The union hack is definitely undefined behavior, right?
Yes and no. According to the standard, it is definitely undefined behavior. But it is such a commonly used trick that GCC and MSVC and as far as I know, every other popular compiler, explicitly guarantees that it is safe and will work as expected.
The following does not violate the aliasing rule, because it has no use of lvalues accessing different types anywhere
template<typename B, typename A>
B noalias_cast(A a) {
union N {
A a;
B b;
N(A a):a(a) { }
};
return N(a).b;
}
unsigned bar(float x) {
return noalias_cast<unsigned>(x);
}
If you really want to be agnostic about the size of the float type and just return the raw bits, do something like this:
void float_to_bytes(char *buffer, float f) {
union {
float x;
char b[sizeof(float)];
};
x = f;
memcpy(buffer, b, sizeof(float));
}
Then call it like so:
float a = 12345.6789;
char buffer[sizeof(float)];
float_to_bytes(buffer, a);
This technique will, of course, produce output specific to your machine's byte ordering.
I want to use the STL's Map container to lookup a pointer by using binary data as a key so I wrote this custom function object:
struct my_cmp
{
bool operator() (unsigned char * const &a, unsigned char * const &b)
{
return (memcmp(a,b,4)<0) ? true : false;
}
};
And using it like this:
map<unsigned char *, void *, my_cmp> mymap;
This compiles and seems to work, but I'm not sure what an "unsigned char * const &" type is and why it didn't work with just "unsigned char *"?
You need to provide a comparator that guarantees non-modifying of the passed values, hence the const (note that it applies to the pointer not the char). As for the reference operator (&), you don't need it -- it's optional. This will also compile:
struct my_cmp
{
bool operator() (unsigned char * const a, unsigned char * const b)
{
return memcmp(a,b,4) < 0;
}
};
It works for me with just unsigned char *.