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).
Related
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.
According to the c++ grammar, const int* const p means that what p points to and it' value can't be rewritten.But today I found that if I code like this:
void f(const int* const p)
{
char* ch = (char*) p;
int* q = (int*) ch;
(*q) = 3; //I can modify the integer that p points to
}
In this condition,the keyword "const" will lose it's effect.Is there any significance to use "const"?
You are casting away the constness here:
char* ch = (char*) p;
Effectively, you are saying "I know what I am doing, forget you are const, I accept the consequences." C++ allows you to do stuff like this because sometimes it can be useful/necessary. But it is fraught with danger.
Note that if the argument passed to the function were really const, then your code would result in undefined behaviour (UB). And you have no way of knowing from inside the function.
Note also that in C++ it is preferable to make your intent clear,
int* pi = const_cast<int*>(p);
This makes it clear that your intention is to cast away the const. It is also easier to search for. The same caveats about danger and UB apply.
Your example will crash the app if const int* const p points to a compile time constant, when casting away constancy you need to be sure what you are doing.
C++ is a language for adults, extra power will never be sacrificed for ephemeral safety, it is the code author's choice whether to stay in a safe zone or to use cast operators and move one step closer to C/asm.
C/C++ will let you do many things that allow you to 'hurt' yourself. Here, casting away the const of p is "legal" because the compiler assumes you know what you are doing. Whether this is good coding style or not is another matter.
When you do something like this, you assume responsibility for any side effects and issues it could create. Here, if the memory pointed to in the parameter is static memory, the program will likely crash.
In short, just because you can do something doesn't mean it is a good idea.
The const keyword is a way to use the compiler to catch programming mistakes, nothing more. It makes no claims about the mutability of memory at runtime, only that the compiler should shout at you if you directly modify the value (without using C-style casts).
A C-style cast is pretty much a marker saying 'I know what I'm doing here'. Which in most instances is false.
Here you change the type of the pointer. Using such a cast (C-type) cast you can change it to any possible pointer with no problem.
The same way you can use c++ cast: const_cast<...>(...):
int* p_non_const = const_cast<int*>(p);
In this case (I hope) you see immediately what is happening - you simply rid of the constness.
Note that in your program you also don't need temprorary variable ch. You can do it directly:
int* q = (int*) p;
In principle you should not use such a cast, because correctly designed and written program doesn't need it. Usually the const_cast is used for quick and temporary changes in the program (to check something) or to use a function from some unproperly designed library.
Is there a difference between pointer to integer-pointer (int**) and pointer to character-pointer (char**), and any other case of pointer to pointer?
Isn't the memory block size for any pointer is the same, so the sub-datatype doesn't play a role in here?
Is it just a semantic distinction with no other significance?
Why not to use just void**?
Why should we use void** when you want a pointer to a char *? Why should we not use char **?
With char **, you have type safety. If the pointer is correctly initialized and not null, you know that by dereferencing it once you get a valid char * - and by dereferencing that pointer, in turn, you get a char.
Why should you ignore this advantage in type safety, and instead play pointer Russian roulette with void**?
The difference is in type-safety. T** implicitly interprets the data as T. void**, however, needs to be manually casted first. And no, pointers are not all 4 / 8 bytes on 32 / 64bit architectures respectively. Member function pointers, for instance, contain offset information too, which needs to be stored in the pointer itself (in the most common implementation).
Most C implementations use the same size and format for all pointers, but this is not required by the C standard.
Some machines do not have byte addressing, so the C implementation implements it by using shifts and other operations. In these implementations, pointers to larger types, such as int, may be normal addresses, but pointers to char would have to have both a machine address and a byte-within-word offset.
Additionally, C makes use of the type information for a variety of purposes, including reducing mistakes made by programmers (possibly giving warnings or errors when you attempt to use a pointer to int where a pointer to float is needed) and optimization. Regarding optimization, consider this example:
void foo(float *array, int *limit)
{
for (int i = 0; i < *limit; ++i)
array[i] = <some calculation>;
}
The C standard says a compiler may use the fact that array and limit are pointers to different types to conclude that they do not overlap. Given this rule, the C implementation may evaluate *limit once when the loop starts, because it knows it will not change during the loop. Without this rule, the compiler would have to assume that one of the assignments to array[i] might change *limit, and it would have to load *limit from memory in each iteration.
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.
Given a void pointer, if I want to make the void pointer point to x bytes ahead, how will this be best done? Is there a better way than casting to a char pointer?
Is there a better way than casting to
a char pointer?
No (except having a char * instead of a void * to begin with, so you don't have to cast it at all).
If this is not desirable or possible, then the only way is:
ptr = static_cast<char *>(ptr) + offset;
(Note: if you are doing this sort of stuff in C++, usually there is a much better solution. Unless you are an expert and you already ruled out every other alternative, I suggest you post a new question asking if there is a better way to do what you're trying to do!)
Take a look at this question, and this question. To summarise, the answer is to cast to char * for arithmetic at a byte level.
Given a void pointer, if I want to make the void pointer point to x bytes ahead, how will this be best done? Is there a better way than casting to a char pointer?
If you have a void*, you don't know that "x bytes ahead" is a valid address. You don't know that creating such a pointer won't crash your program.
And that is why it can't be done with void*.
You can only perform pointer arithmetics on pointers into an array. And if you have a pointer into an array, you know the type of the array, and can use the equivalent pointer type.
If you want some kind of abstract "byte pointer" (say, if you're implementing a memory pool and need to point to a specific offset into a buffer), you should use char* or unsigned char*, not void*.
When doing pointer arithmetic compiler wants to take into account what it knows about the type that the pointer points to.
For example if you have a int *myint. Then these two statements actually do the same thing:
int a = *(myint+5);
and
int a = myint[5];
in this case myint+5 does not mean "the address of myint plus 5" but "the address of myint plus 5*sizeof(int))"
So in case of a void * the compiler can't make any assumptions what void * + 5 should mean. So before you use a void * it kind of forces you to specify how you want to use it.
you can convert the pointer to normal integer , do the increment or whatever operation , then you can assign the integer to that pointer , hope it helps
Here was my problem
void *inputAudioBuffer;
c++ was not letting me do this
UInt16 *inputBuffer = (UInt16 *)(inputAudioBuffer + inputBufferOffset);
after doing a type cast I was able to do it
UInt16 *inputBuffer = (UInt16 *)( (UInt16 *) inputAudioBuffer + inputBufferOffset);
In difference to the other people answering this question, it seems to me as if a simple +x (no casting at all) is sufficient to access the address x bytes ahead of your void pointer. The compiler might not like it, but at least in the cases I have used this, it has worked. I'm using g++ (gcc)...
So as long as you know what you're doing, no probs.