Why does pointer to int convert to void* but pointer to function convert to bool?
Based on the above, it is perfectly OK to convert a function pointer or a pointer to an
int
to avoid*
as well asbool
.
The quotation states that a pointer to an object can be converted to cv void *
. Functions are not objects, and this disqualifies the conversion to cv void *
, leaving only bool
.
However, given the choice of both, which one should a pointer convert to?
It should convert to const void *
over bool
. Why? Well, prepare for a journey that starts in Overload Resolution (§13.3 [over.match]/2). Emphasis mine, of course.
But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:
— First, a subset of the candidate functions (those that have the proper number of arguments and meet
certain other conditions) is selected to form a set of viable functions (13.3.2).— Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.
So what about these implicit conversion sequences?
Let's jump over to §13.3.3.1 [over.best.ics]/3 and see just what an implicit conversion sequence is:
A well-formed implicit conversion sequence is one of the following forms:
— a standard conversion sequence (13.3.3.1.1),
— a user-defined conversion sequence (13.3.3.1.2), or
— an ellipsis conversion sequence (13.3.3.1.3).
We're interested in standard conversions sequences. Let's pop over to Standard Conversion Sequences (§13.3.3.1.1 [over.ics.scs]):
1 Table 12 summarizes the conversions defined in Clause 4 and partitions them into four disjoint categories: Lvalue Transformation, Qualification Adjustment, Promotion, and Conversion. [ Note: These categories are orthogonal with respect to value category, cv-qualification, and data representation: the Lvalue Transformations do not change the cv-qualification or data representation of the type; the Qualification Adjustments do not change the value category or data representation of the type; and the Promotions and Conversions do not change the value category or cv-qualification of the type. — end note ]
2 [ Note: As described in Clause 4, a standard conversion sequence is either the Identity conversion by itself (that is, no conversion) or consists of one to three conversions from the other four categories.
The important part is in /2. A standard conversion sequence is allowed to be a single standard conversion. These standard conversions are listed in Table 12, shown below. Notice that both your Pointer Conversions and Boolean Conversions are in there.
From here, we learn something important: Pointer conversions and boolean conversions have the same rank. Remember that as we head to Ranking Implicit Conversion Sequences (§13.3.3.2 [over.ics.rank]).
Looking at /4, we see:
Standard conversion sequences are ordered by their ranks: an Exact Match is a better conversion than a Promotion, which is a better conversion than a Conversion. Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies:
— A conversion that does not convert a pointer, a pointer to member, or std::nullptr_t to bool is
better than one that does.
We've found our answer in the form of a very explicit statement. Hooray!
C++, does bool conversion always fall back to implicit conversion to void*?
If the compiler cannot convert a user-defined type to bool
directly, then it tries to do it indirectly, i.e. convert (via an user-defined conversion) to a type that can be converted to bool
without involving another user-defined conversion. The list of such types includes (and seems to be limited to) the following types:
- an integer arithmetic type (
char
,int
, etc) - a floating point arithmetic type (
float
,double
,long double
) - a pointer type (
void*
belongs here, but it could as well beconst std::vector<Something>*
) - a pointer to function (including a pointer to a member function)
- a reference type to any of the above
Note however that only one such indirect conversion must exist. If two or more conversions from the above list are possible, then the compiler will face an ambiguity and will report an error.
Bug casting from bool* to void* to int*
static_cast<int*>(ptr)[0]
casts ptr
to int*
and reads the first element. Since the original array is only 2 bytes, you're reading outside it (because you're reading a 4-byte int
) and invokes undefined behavior, unless int
is a 2-byte type on your system. You're also violating the strict aliasing rule by accessing a type using a different pointer type which also invokes UB. Besides you'll get UB if the bool array isn't properly aligned. On x86 it doesn't cause any problems because x86 allows unaligned access by default but you'll get a segfault on most other architectures
static_cast<int>(test[0])
OTOH converts test[0]
(which is a bool
) to int
and is a completely valid value conversion.
Update:
The type
int*
refers to a pointer whose object is 4-bytes long, whereasbool*
refers to a pointer whose object is 2-bytes long
No. When dereferencing a variable var
, an amount of memory of length sizeof(var)
will be read from memory starting from that address and treat as the value of that variable. So *bool_ptr
will read 1 byte and *int_ptr
will read 4 bytes from memory (if bool
and int
are 1 and 4-byte types respectively)
In your case the bool
array contains 2 bytes, so when 4 bytes is read from static_cast<int*>(ptr)
, 2 byte inside the array and 2 bytes outside the array are read. If you declared bool test[4] = {};
(or more elements) you'll see that the int*
dereferencing completes successfully because it reads all 4 bools that belong to you, but you still suffer from the unalignment issue
Now try changing the bool values to nonzero and see
bool test[4] = { true, false, true, false };
You'll quickly realize that casting a pointer to a different pointer type isn't a simple read in the old type and convert to the new type like a simple value conversion (i.e. a cast) but a different "memory treatment". This is essentially just a reinterpret_cast
which you can read to understand more about this problem
I don't understand what you are saying about
char*
. You're saying casting from any type tochar*
is valid?
Casting from any other pointer types to char*
is valid. Read the question about strict aliasing rule above:
You can use
char*
for aliasing instead of your system's word. The rules allow an exception forchar*
(includingsigned char
andunsigned char
). It's always assumed thatchar*
aliases other types.
It's used for things like memcpy
where you copy the bytes representing a type to a different destination
bool test[4] = { true, true, true, true };
int v;
memcpy((char*)&test, (char*)&v, sizeof v);
Technically mempcy
receives void*
, the cast to char*
is just used for demonstration
See also
- Strict aliasing rule and 'char *' pointers
- https://en.wikipedia.org/wiki/Pointer_aliasing
Why can I cast int and BOOL to void*, but not float?
BOOL is not a C++ type. It's probably typedef or defined somewhere, and in these cases, it would be the same as int. Windows, for example, has this in Windef.h:
typedef int BOOL;
so your question reduces to, why can you typecast int to void*, but not float to void*?
int to void* is ok but generally not recommended (and some compilers will warn about it) because they are inherently the same in representation. A pointer is basically an integer that points to an address in memory.
float to void* is not ok because the interpretation of the float value and the actual bits representing it are different. For example, if you do:
float x = 1.0;
what it does is it sets the 32 bit memory to 00 00 80 3f (the actual representation of the float value 1.0 in IEEE single precision). When you cast a float to a void*, the interpretation is ambiguous. Do you mean the pointer that points to location 1 in memory? or do you mean the pointer that points to location 3f800000 (assuming little endian) in memory?
Of course, if you are sure which of the two cases you want, there is always a way to get around the problem. For example:
void* u = (void*)((int)x); // first case
void* u = (void*)(((unsigned short*)(&x))[0] | (((unsigned int)((unsigned short*)(&x))[1]) << 16)); // second case
Why function pointer address is printing in bool type in c++?
Function pointers aren't convertible to data pointers. You'd get a compiler error if you were to try and assign one to a void*
variable. But they are implicitly convertible to bool
!
That is why the bool
overload for operator<<
is chosen over the const void*
one.
To force the overload you want, you'd need to use a very strong C++ cast, that will almost completely ignore the static type information.
#include<iostream>
using namespace std;
int add(int x, int y)
{
int z;
z = x+y;
cout<<"Ans:"<<z<<endl;
}
int main()
{
int a=10, b= 10;
int (*func_ptr) (int,int);
func_ptr = &add;
cout<<"The address of function add()is :"<< reinterpret_cast<void*>(func_ptr) <<endl;
(*func_ptr) (a,b);
}
Note that casting and treating function pointers as data pointers is only conditionally supported (from the C++ standard standpoint). Using it for anything other than casting back to the same function pointer will have an implementation specific outcome, that can very greatly among compilers.
Is failure to implicitly convert a pointer to _Bool a compiler deficiency?
Yes, this is a compiler bug. While C has no implicit conversions in either direction between integer types and pointer types, nor implicit conversions between pointer types except in special cases like to/from pointer-to-void or from pointer-to-unqualified to pointer-to-qualified, it does define an implicit conversion to _Bool
. (Traditionally many compilers supported such implicit conversions in other places, but doing so was harmful and was not part of the C language.)
The language about implicit conversion is under 6.5.16.1 Simple assignment:
One of the following shall hold:
- the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;
- the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;
- the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
- the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
- the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
- the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.
In other places in the standard where implicit conversion appears, it's specified "as if by assignment", referring to the above. For example, in 6.5.2.2 Function calls:
If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, ...
Note that your question is actually about initialization, which is not assignment in C but something different. However, 6.7.9 Initialization ¶11 covers it:
The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.
How can converting a pointer to `void*` twice be invalid?
The thing you're asking about was a contrived example, meant to illustrate a corner case of the rules of C, and the thing that's invalid isn't the double cast, it's the assignment.
If you have any pointer-to-function type, such as
typedef void (*fp)(void);
you can initialize variables of this type with any valid null pointer constant, e.g.
fp a = 0; // canonical null pointer constant in C
fp b = (void *)0; // another common choice
fp c = '\0'; // yes, really, this is a null pointer constant
fp d = (1-1); // and so is this
But you can't initialize them with a pointer to any specific type other than fp
itself, even if that pointer is a null pointer, and even if the specific type in question is void *
.
char *x = 0;
void *y = 0;
fp e = x; // invalid: no assignment conversion from `char *` to `fp`
fp f = y; // invalid: no assignment conversion from `void *` to `fp`
The line from my old answer that you were confused by,
fp g = (void *)(void *)0;
is essentially the same as fp f = y
above. The right-hand side of both assignments is a null pointer with type void *
, but not a null pointer constant, so the assignment is invalid.
You are probably now wondering why (void *)(void *)0
isn't a null pointer constant, even though (void *)0
is a null pointer constant. This is just the way the C standard happens to be written: a null pointer constant is defined as any integer constant expression with value 0, possibly with one cast to void *
in front of it. Any extra casts and it's no longer a null pointer constant (but is still a constant expression). (Integer constant expressions cannot contain internal casts to pointer types.)
In your contrasting example
int a;
int *pa = (int *)&a;
no null pointers are involved, and no integer constant expressions either, and the cast really is 100% redundant. &a
could be a constant expression (if and only if a
has static storage duration), but it is not an integer constant expression.
Why does std::cout convert volatile pointers to bool?
ostream::operator<<
has the following overloads, among others:
ostream& operator<< (bool val );
ostream& operator<< (const void* val );
When you pass in a volatile pointer, the second overload can't apply because volatile pointers cannot be converted to non-volatile without an explicit cast. However, any pointer can be converted to bool, so the first overload is chosen, and the result you see is 1 or 0.
So the real reason for this is not an intentional decision on behalf of the standards committe, but simply that the standard does not specify an overload that takes a volatile pointer.
Casting object pointer to double void pointer (pointer to pointer to void)
For all intents and purposes a void
pointer can hold addresses of any object (data type), i.e. it can point to any object, and can be typecasted to any object, your code is valid, I would just use a more idiomatic cast:
Q->pop(reinterpret_cast<void**>(&buf), size, sn);
§7.3.12 Pointer conversions [conv.ptr]
- A prvalue of type “pointer to cv
T
”, whereT
is an object type, can be converted to a prvalue of type “pointer to cvvoid
”. The pointer value (6.8.3) is unchanged by this conversion.
Example:
void example(void **packet){
std::cout << *packet << "\n"; // pointer value
std::cout << packet << "\n"; // pointer address
std::cout << **reinterpret_cast<int**>(packet); // value
}
int main()
{
int* x = new int(20);
std::cout << x << "\n"; // pointer value
std::cout << &x << "\n"; // pointer address
example(reinterpret_cast<void**>(&x));
delete x;
}
Output:
0xb83eb0
0x7ffc181ab2c8
0xb83eb0
0x7ffc181ab2c8
20
The explicit cast is even only needed because it's a pointer to pointer otherwise the conversion would be implicit, no cast would be needed.
bool vs void* casts on the same object
In an if
statement, implicit and explicit conversion operators are considered. Because A
has an operator bool
, it chooses that one, as it is a better match than converting A
to a void*
and then converting that to bool
.
But in every other statement, which are not conditions (if
, while
, ...), the explicit conversion operators do not participate in overload resolution, and the only valid operator then is operator void*
, which can be used because there is an implicit conversion from pointers to bool
.
If you want operator bool
to be selected, you need make it non-explicit
, or use a cast (because that's what marking it explicit
means, making sure that one has to be explicit to use it):
f(static_cast<bool>(a));
Related Topics
Does Std::Cout Have a Return Value
How Serious Is the New/Delete Operator Mismatch Error
Erasing Vector::End from Vector
Glut Deprecation in MAC Osx 10.9, Ide: Qt Creator
Pointer Array and Sizeof Confusion
Brace Initialization for Inherited Pod
Are the "Usual Arithmetic Conversions" and the "Integer Promotions" the Same Thing
C++ When Is It Ok to Extend the 'Std' Namespace
Enumdisplaydevices VS Wmi Win32_Desktopmonitor, How to Detect Active Monitors
How to Load a Bmp on Glut to Use It as a Texture
What Is the Purpose of the _Chkstk() Function
Why Do Lambda Functions Drop Deduced Return Type Reference by Default
Multiple Inheritance: Unexpected Result After Cast from Void * to 2Nd Base Class