I'm not familiar in C++ casting and I want to convert my C style casting to a C++ casting. Here is my code,
typedef unsigned char u8;
u8 sTmp[20] = {0};
//.. code to put string data in sTmp
char* sData;
sData = (char*)&(sTmp[0]);
Here, I want to convert (char*)&(sTmp[0]) to a C++ casting.
Many thanks.
Your cast is unnecessarily complicated. You get the first element of the array and then the address of that element. On expressions, arrays decay into pointers, so you can get the address of the array by its name alone:
sData = (char*)sTmp;
Like #Richard said above, the best way to do the cast on C++ is using reinterpret_cast, like this:
sData = reinterpret_cast<char*>(sTmp);
Finally, sTemp (like I already mentioned) will decay to a pointer on expressions, specifically an unsigned char* (which is the usual way of addressing raw memory), so it is very likely that you don't actually need to cast it to char* at all. (unless you have to print it, which doesn´t seem right anyway)
Related
I have a const uint8_t* that I want to convert to a char* for an interface that expects a char*.
The easiest way to do this is with a C-style cast:
const uint8_t* aptr = &some_buffer;
char* bptr = (char*)aptr;
However, our internal style guide (which is based on the Google C++ Style Guide) bans C-style casts.
Another option is this monstrosity, which I find pretty unreadable:
char *cptr = reinterpret_cast<char*>(const_cast<uint8_t*>(aptr));
These other options I tried all failed to compile:
char* dptr = reinterpret_cast<char*>(aptr);
char* eptr = const_cast<char*>(aptr);
char* fptr = static_cast<char*>(aptr);
Is there any way I can perform this cast using a C++-style cast without nesting two separate cast operations?
Is there any way I can perform this cast using a C++-style cast without nesting two separate cast operations?
Not portably, no. There is no single "the type is wrong and the const is also wrong" cast.
Another option is this monstrosity, which I find pretty unreadable:
char *cptr = reinterpret_cast<char*>(const_cast<uint8_t*>(ptr));
Do that.
Both C++ casts and your internal style guide are striving to make this look monstrous.
You can prevent the repetition of these casts by writing your own cast.
template< typename T >
char* awful_monster_cast( const T * ptr )
{
return reinterpret_cast<char*>(const_cast<T*>(ptr));
}
Is there any way I can perform this cast using a C++-style cast without nesting two separate cast operations?
If you want it done in a single line like char* foo = some_cast(source) then no. The only cast that can remove const is const_cast so you need that plus an additional one to convert that now non const pointer into your source type. That leaves you with the monstrosity
char *cptr = reinterpret_cast<char*>(const_cast<uint8_t*>(aptr));
as the single line solution. This is a safety feature and makes it so it is painfully obvious you are removing constness.
Another option is this monstrosity, which I find pretty unreadable:
char *cptr = reinterpret_cast<char*>(const_cast<uint8_t*>(aptr));
You might find it unreadable, but this is the idiomatic way to express this conversion in C++.
Here's what's important:
You are using a C-style API that, for whatever reason, is not itself const-correct, but you want to preserve the const-correctness of your own code, as much as possible, necessitating a cast to remove the cv-qualifications of the type.
The C-style API uses signed data types, whereas your application uses unsigned data types.
In total, those are two conversions that your code needs to make—removing the const-ness, and converting to a signed type. This demands that you make two explicitly expressed conversions, if you want to obey these coding practices. You may not agree with this principle, but your company/coding practices certainly do.
Of course, I don't think anything is stopping you from writing something like this:
char * convert_to_c_data_buffer(uint8_t const* ptr) {
return reinterpret_cast<char*>(const_cast<uint8_t*>(ptr));
}
char* dptr = convert_to_c_data_buffer(aptr);
Is there any way I can perform this cast using a C++-style cast without nesting two separate cast operations?
Certainly. There is no need to nest those cast operations. Instead, you can use two separate expressions:
auto cuint = const_cast<uint8_t*>(aptr);
auto cptr = reinterpret_cast<char*>(cuint);
I know legacy is always a justification, but I wanted to check out this example from MariaDB and see if I understand it enough to critique what's going on,
static int show_open_tables(THD *, SHOW_VAR *var, char *buff) {
var->type = SHOW_LONG;
var->value = buff;
*((long *)buff) = (long)table_cache_manager.cached_tables();
return 0;
}
Here they're taking in char* and they're writing it to var->value which is also a char*. Then they force a pointer to a long in the buff and set the type to a SHOW_LONG to indicate it as such.
I'm wondering why they would use a char* for this though and not a uintptr_t -- especially being when they're forcing pointers to longs and other types in it.
Wasn't the norm pre-uintptr_t to use void* for polymorphism in C++?
There seems to be two questions here. So I've split my answer up.
Using char*
Using a char* is fine. Character types (char, signed char, and unsigned char) are specially treated by the C and C++ standards. The C standard defines the following rules for accessing an object:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
a type compatible with the effective type of the object,
a qualified version of a type compatible with the effective type of the object,
a type that is the signed or unsigned type corresponding to the effective type of the object,
a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
a character type.
This effectively means character types are the closest the standards come to defining a 'byte' type (std::byte in C++17 is just defined as enum class byte : unsigned char {})
However, as per the above rules casting a char* to a long* and then assigning to it is incorrect (although generally works in practice). memcpy should be used instead. For example:
long cached_tables = table_cache_manager.cached_tables();
memcpy(buf, &cached_tables, sizeof(cached_tables));
void* would also be a legitimate choice. Whether it is better is a mater of opinion. I would say the clearest option would be to add a type alias for char to convey the intent to use it as a byte type (e.g. typedef char byte_t). Of the top of my head though I can think of several examples of prominent libraries which use char as is, as a byte type. For example, the Boost memory mapped file code gives a char* and leveldb uses std::string as a byte buffer type (presumably to taking advantage of SSO).
Regarding uinptr_t:
uintptr_t is an optional type defined as an unsigned integer capable of holding a pointer. If you want to store the address of a pointed-to object in an integer, then it is a suitable type to use. It is not a suitable type to use here.
they're taking in char* and they're writing it to var->value which is also a char*. Then they force a pointer to a long in the buff and set the type to a SHOW_LONG to indicate it as such.
Or something. That code is hideous.
I'm wondering why they would use a char* for this though and not a uintptr_t -- especially being when they're forcing pointers to longs and other types in it.
Who knows? Who knows what the guy was on when he wrote it? Who cares? That code is hideous, we certainly shouldn't be trying to learn from it.
Wasn't the norm pre-uintptr_t to use void* for polymorphism in C++?
Yes, and it still is. The purpose of uintptr_t is to define an integer type that is big enough to hold a pointer.
I wanted to check out this example from MariaDB and see if I understand it enough to critique what's going on
You might have reservations about doing so but I certainly don't, that API is just a blatant lie. The way to do it (if you absolutely have to) would (obviously) be:
static int show_open_tables(THD *, SHOW_VAR *var, long *buff) {
var->type = SHOW_LONG;
var->value = (char *) buff;
*buff = (long)table_cache_manager.cached_tables();
return 0;
}
Then at least it is no longer a ticking time bomb.
Hmmm, OK, maybe (just maybe) that function is used in a dispatch table somewhere and therefore needs (unless you cast it) to have a specific signature. If so, I'm certainly not going to dig through 10,000 lines of code to find out (and anyway, I can't, it's so long it crashes my tablet).
But if anything, that would just make it worse. Now that timebomb has become a stealth bomber. And anyway, I don't believe it's that for a moment. It's just a piece of dangerous nonsense.
Code:
void *buff;
char *r_buff = (char *)buff;
I can't understand the type casting of buff. Please help.
Thank you.
buff is a pointer to some memory, where the type of its content is unspecified (hence the void).
The second line tells that r_buff shall point to the same memory location, and the contents shall be interpreted as char(s).
buff is typed as a void pointer, which means it points to memory without declaring anything about the contents.
When you cast to char *, you declare that you're interpreting the pointer as being a char pointer.
In well written C++, you should not use C-style casts. So your cast should look like this:
void *buff;
char *r_buff = static_cast<char *>(buff);
See here for an explanation of what the C++ casting operators do.
By its name, buff is likely to be a memory buffer in which to write data, possibly binary data.
There are reasons why one might want to cast it to char *, potentially to use pointer arithmetic on it as one is writing because you cannot do that with a void*.
For example if you are supplied also a size (likely) and your API requires not pointer and size but 2 pointers (begin and end) you will need pointer arithmetic to determine where the end is.
The code could well be C in which case the cast is correct. If the code is C++ though a static_cast is preferable although the C cast is not incorrect in this instance. The reason a static_cast is generally preferred is that the compiler will catch more occasions when you cast incorrectly that way, and it is also more easily greppable. However casting in general breaks type-safety rules and therefore is preferably avoided much of the time. (Not that it is never correct, as it may be here).
I'm designing a Buffer class whose purpose is to represent a chunk of memory.
My underlying buffer is a char* (well, a boost::shared_array<char> actually, but it doesn't really matter).
I'm stuck at deciding what prototype to choose for my constructor:
Should I go with:
Buffer(const void* buf, size_t buflen);
Or with:
Buffer(const char* buf, size_t buflen);
Or something else ?
What is usually done, and why ?
API interface is more clear for user, if buffer has void* type, and string has char* type. Compare memcpy and strcpy function definitions.
For the constructor and other API functions, the advantage of void* is that it allows the caller to pass in a pointer to any type without having to do an unnecessary cast. If it makes sense for the caller to be able to pass in any type, then void* is preferable. If it really only makes sense for the caller to be able to pass in char*, then use that type.
C++17
C++17 introduced std::byte specifically for this.
Its definition is actually simple: enum class byte : unsigned char {};.
I generally used unsigned char as the underlying structure (don't want signedness to mess up with my buffer for I know what reason). However I usually typedefed it:
// C++11
using byte = unsigned char;
// C++98
typedef unsigned char byte;
And then refer to it as byte* which neatly conveys the meaning in my opinion, better than either char* or void* at least.
I'd prefer char*, because for me personally it plays better with being "a buffer". void* seems more like "a pointer to I don't know what". Besides, it is what your underlying is, anyway.
I'd recommend uint8_t, which is defined in stdint.h. It's basically the same thing as the "typedef unsigned char byte;" that others have been recommending, but it has the advantage of being part of the C standard.
As for void*, I would only use that for polymorphism. ie. I'd only call something a void pointer if I didn't yet know what type of thing it would be pointing to. In your case you've got an array of bytes, so I'd label it as such by using uint8_t* as the type.
I prefer unsigned char * or uint8_t * for buffer implementations, since void * has the annoying restriction that you can't perform pointer math on it. So if you want to process some data at some offset from the buffer, or just break your buffer up into chunks or whatever, you are stuck casting to some other type anyway to do the math.
I prefer unsigned char * or uint8_t * over plain char * because of the special rules regarding aliasing and char *, which has the potential to seriously pessimize some loops working on your buffers.
Can someone explain this to me:
char* a;
unsigned char* b;
b = a;
// error: invalid conversion from ‘char*’ to ‘unsigned char*’
b = static_cast<unsigned char*>(a);
// error: invalid static_cast from type ‘char*’ to type ‘unsigned char*’
b = static_cast<unsigned char*>(static_cast<void*>(a));
// everything is fine
What makes the difference between cast 2 and 3? And are there any pitfalls if the approach from 3 is used for other (more complex) types?
[edit]
As some mentioned bad design, etc...
This simple example comes from an image library which gives me the pointer to the image data as char*. Clearly image intensities are always positive so I need to interpret it as unsigned char data.
static_cast<void*> annihilate the purpose of type checking as you say that now it points on "something you don't know the type of". Then the compiler have to trust you and when you say static_cast<unsigned char*> on your new void* then he'll just try to do his job as you ask explicitely.
You'd better use reinterpret_cast<> if you really must use a cast here (as it's obvioulsy showing a design problem here).
Your third approach works because C++ allows a void pointer to be casted to T* via static_cast (and back again) but is more restrictive with other pointer types for safety reasons. char and unsigned char are two distinct types. This calls for a reinterpret_cast.
C++ tries to be a little bit more restrictive to type casting than C, so it doesn't let you convert chars to unsigned chars using static_cast (note that you will lose sign information). However, the type void* is special, as C++ cannot make any assumption for it, and has to rely on the compiler telling it the exact type (hence the third cast works).
As for your second question, of course there are a lot of pitfals on using void*. Usually, you don't have to use it, as the C++ type system, templates, etc. is rich enough to not to have to rely in that "unknown type". Also, if you really need to use it, you have to be very careful with casts to and from void* controlling that types inserted and obtained are really the same (for example, not pointer to subclasses, etc.)
static_cast between pointers works correct only if one of pointers is void or that's casting between objects of classes, where one class is inherited by another.
The difference between 2 and 3 is that in 3, you're explicitly telling the compiler to stop checking you by casting to void*. If the approach from 3 is used for, pretty much anything that isn't a direct primitive integral type, you will invoke undefined behaviour. You may well invoke undefined behaviour in #3 anyway. If it doesn't cast implicitly, it's almost certainly a bad idea unless you really know what's going on, and if you cast a void* back to something that wasn't it's original type, you will get undefined behaviour.
Casts between pointers require reinterpret_cast, with the exception of void*:
Casts from any pointer to to void* are implicit, so you don't need to explicitly cast:
char* pch;
void* p = pch;
Casts from void* to any other pointer only require a static_cast:
unsigned char* pi = static_cast<unsigned char*>(p);
beware, when you cast to void* you lose any type information.
what you are trying to do is incorrect, and false, and error prone and misleading. that's why the compilator returned a compilation error :-)
a simple example
char* pChar = NULL; // you should always initalize your variable when you declare them
unsigned char* pUnsignedChar = NULL; // you should always initalize your variable when you declare them
char aChar = -128;
pChar = &aChar;
pUnsignedChar = static_cast<unsigned char*>(static_cast<void*>(pChar));
then, though pUnsignedChar == pChar nonethless we have *pUnsignedChar == 255 and *pChar == -128.
i do believe this is bad joke, thus bad code.