The behavior of my code is different in c and c++.
void *(*funcPtr)() = dlsym(some symbol..) ; // (1) works in c but not c++
int (*funcPtr)();
*(void**)(&funcPtr) = dlsym(some symbol..) ; // (2) works in c++
I dont understand how the 2nd casting works in c++ while the 1st casting doesnt work in c++. The error message for (1) show is invalid conversion from void* to void*() in c++.
The problem is that dlsym returns a void* pointer. While in C, any such pointer is implicitly convertible into any other (object!) pointer type (for comparison: casting the result of malloc), this is not the case in C++ (here you need to cast the result of malloc).
For function pointers, though, this cast is not implicit even in C. Apparently, as your code compiles, your compiler added this implicit cast for function pointers, too, as a compiler extension (in consistency with object pointers); however, for being fully standard compliant, it actually should issue a diagnostic, e. g. a compiler warning, mandated by C17 6.5.4.3:
Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast.
But now instead of casting the target pointer, you rather should cast the result of dlsym into the appropriate function pointer:
int (*funcPtr)() = reinterpret_cast<int(*)()>(dlsym(some symbol..));
or simpler:
auto funcPtr = reinterpret_cast<int(*)()>(dlsym(some symbol..));
or even:
int (*funcPtr)() = reinterpret_cast<decltype(funcPtr)>(dlsym(some symbol..));
(Last one especially interesting if funcPtr has been declared previously.)
Additionally, you should prefer C++ over C style casts, see my variants above. You get more precise control over what type of cast actually occurs.
Side note: Have you noticed that the two function pointers declared in your question differ in return type (void* vs. int)? Additionally, a function not accepting any arguments in C needs to be declared as void f(void); accordingly, function pointers: void*(*f)(void). C++ allows usage of void for compatibility, while skipping void in C has totally different meaning: The function could accept anything, you need to know from elsewhere (documentation) how many arguments of which type actually can be passed to.
Strictly speaking, none of this code is valid in either language.
void *(*funcPtr)() = dlsym(some symbol..) ;
dlsym returns type void* so this is not valid in either language. The C standard only allows for implicit conversions between void* and pointers to object type, see C17 6.3.2.3:
A pointer to void may be converted to or from a pointer to any object type. A pointer to
any object type may be converted to a pointer to void and back again; the result shall
compare equal to the original pointer.
Specifically, your code is a language violation of one of the rules of simple assignment, C17 6.5.16.1, emphasis mine:
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 reason why it might compile on certain compilers is overly lax compiler settings. If you are for example using gcc, you need to compile with gcc -std=c17 -pedantic-errors to get a language compliant compiler, otherwise it defaults to the non-standard "gnu11" language.
int (*funcPtr)();
*(void**)(&funcPtr) = dlsym(some symbol..) ; // (2) works in c++
Here you explicitly force the function pointer to become type void**. The cast is fine syntax-wise, but this may or may not be a valid pointer conversion on the specific compiler. Again, conversions between object pointers and function pointers are not supported by the C or C++ standard, but you are relying on non-standard extensions. Formally this code invokes undefined behavior in both C and C++.
In practice, lots of compilers have well-defined behavior here, because most systems have the same representation of object pointers and function pointers.
Given that the conversion is valid, you can of course de-reference a void** to get a void* and then assign another void* to it.
Related
This can be compiled (despite being UB (right?) because fvp == nullptr)
int f;
void* fvp{};
decltype(f)* fp = static_cast<decltype(f)*>(fvp);
but this cannot
void f() {}
void* fvp{};
decltype(f)* fp = static_cast<decltype(f)*>(fvp);
because (Clang says)
Static_cast from 'void *' to 'decltype(f) ' (aka 'void ()()') is not allowed [bad_cxx_cast_generic]
Why is this the case? And where from the standard do I understand this? I guess [expr.static.cast] is where I should look at; specifically 7, but I'm not sure.
Follow up question on the reason why I wanted to ask this one.
This is not allowed because [expr.static_cast] does not allow it. Indeed, the relevant language is:
No other conversion shall be performed explicitly using a static_cast.
Since there is no conversion listed that would permit conversion from void* to a function pointer type, that conversion is not allowed.
The rationale is that function and data pointers may have different sizes or alignment requirements.
You might consider a reinterpret_cast, which conditionally supports such conversions. But it would be better to use a design that does not require such conversions. If you need to type-erase a function pointer, you will still need reinterpret_cast but can use e.g. void(*)() as the erased type, which is always supported.
where from the standard do I understand this? I guess [expr.static.cast] is where I should look at; specifically 7, but I'm not sure
Basically, there is no guarantee for a full-round trip between void* and a function pointer.
This can be seen from expr.reinterpret.cast#8 which says:
Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning of such a conversion is implementation-defined, except that if an implementation supports conversions in both directions, converting a prvalue of one type to the other type and back, possibly with different cv-qualification, shall yield the original pointer value.
The following code compiles without any error in VSC++2017 and doesn't compile in gcc 7.3.0 (error: invalid static_cast from type ‘int(int)’ to type ‘void*’
void* p = static_cast<void*>(func))
#include <iostream>
int func(int x) { return 2 * x; }
int main() {
void* p = static_cast<void*>(func);
return 0;
}
Functions are implicitly convertible only to function pointers. A function pointer is not a pointer in the strict meaning of the word in the language, which refers only to pointers to objects.
Function pointers cannot be converted to void* using static_cast. The shown program is ill-formed. If a compiler does not warn, then it fails to conform to the standard. Failing to compile an ill-formed program does not violate the standard.
On systems where void* is guaranteed to be able to point to a function (such as POSIX), you can use reinterpret_cast instead:
void* p = reinterpret_cast<void*>(func);
But this is not portable to systems that lack the guarantee. (I know of no system that has a C++ compiler and does not have this guarantee, but that does not mean such system does not exist).
Standard quote:
[expr.reinterpret.cast]
Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning
of such a conversion is implementation-defined, except that if an implementation supports conversions in both
directions, converting a prvalue of one type to the other type and back, possibly with different cv-qualification,
shall yield the original pointer value.
Note that this conditional support does not extend to pointers to member functions. Pointers to member functions are not function pointers.
int func(int n)
{return n;}
int main()
{ cout << func[4] ;
cout << func[4,3,5] ;}
what do these actually mean? I guess it is about accessing func+4 and func is allocated space on calling func[4].
But, func[4,3,5] is just absurd.
The reason this code compiles and func[4] is not a syntax error is:
1.Function types can implicitly convert to pointers of the same type.
So, if we have code like this:
int f(int);
using func_t = int(*)(int);
void g(func_t);
we can write
g(f)
and aren't forced to write g(&f). The &, taking us from type int(int) to int(*)(int) happens implicitly.
2.In C (and necessarily in C++ for compatibility) pointers are connected to arrays, and when p is a pointer p[x] is the same as *(p + x). So func[4] is the same as *(func + 4).
3.*(p+x) has the type of a function int(int), but again can implicitly decay to a pointer type whenever necessary. So *(func + 4) can implicitly just be (func + 4).
4.Pointers of any type are streamable to std::cout.
Note, that just because it isn't a syntax error doesn't mean it is valid. Of course it is undefined behavior, and as the compiler warning emitted by gcc and clang indicates, pointer arithmetic with a function pointer is generally wrong, because you cannot make an array of functions. The implementation places functions however it likes. (You can make an array of function pointers but that is something else entirely.)
Edit: I should correct myself -- this answer is not entirely correct. func[4] is not valid, because the pointer is not a pointer to an object type. #holyblackcat answer is correct, see his answer for reference in the standard.
This code should be ill-formed, and gcc only compiles it without an error because they are using a nonstandard extension by default. Clang and msvc correctly reject this code.
I'm surprised no answer mentions it, but:
The code in the question is simply not valid C++.
It's rejected by Clang and MSVC with no flags. GCC rejects it with -pedantic-errors.
a[b] (in absence of operator overloading) is defined as *(a + b), and the builtin operator + requires the pointer operand to be a pointer to an object type (which functions pointers are not).
[expr.add]/1
...either both operands shall have arithmetic or unscoped enumeration type, or one operand shall be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration type.
(Emphasis mine.)
GCC compiles the code because an extension allowing arithmetic on function pointer is enabled by default.
Due to function-to-pointer decay, func[4] is treated as &(&func)[4], which effectively means &func + 4, which (as the link explains) simply adds 4 to the numerical value of the pointer. Calling resulting pointer will most likely cause a crash or unpredicatble results.
std::cout doesn't have an overload of << suitable for printing function pointers, and the best suitable overload the compiler is able to find is the one for printing bools. The pointer gets converted to bool, and since it's non-null, it becomes true, which is then printed as 1.
Lastly, func[4,3,5] has the same effect as func[5], since in this context , is treated as an operator, and x , y is equal to y.
Since it has not been mentioned yet: func[3, 4, 5] is identical to func[5] - the commas in there are the builtin comma operator which evaluates the left hand side expression, discards it and then evaluates the right hand side expression. There is no function call happening here and the commas in the code are not delimiting function parameters.
Yes,It is about accessing the func+4 which is not already defined leading to a garbage value.So the compiler will indicate you with the following warning message.
hereProgram: In function 'int main()':
Program:7: warning: pointer to a function used in arithmetic
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Correct format specifier to print pointer (address)?
When printing a pointer using printf, is it necessary to cast the pointer to void *? In other words, in code like
#include <stdio.h>
int main() {
int a;
printf("address of a = %p\n", &a);
}
should the argument really be (void *) &a? gcc doesn't seem to give any warnings when no explicit cast is made.
Yes, the cast to void* is required.
int a;
printf("address of a = %p\n", &a);
&a is of type int*; printf's "%p" format requires an argument of type void*. The int* argument is not implicitly converted to void*, because the declaration of printf doesn't provide type information for parameters other than the first (the format string). All arguments after the format string have the default argument promotions applied to them; these promotions do not convert int* to void*.
The likely result is that printf sees an argument that's really of type int* and interprets it as if it were of type void*. This is type-punning, not conversion, and it has undefined behavior. It will likely happen to work if int* and void* happen to have the same representation, but the language standard does not guarantee that, even by implication. And the type-punning I described is only one possible behavior; the standard says literally nothing about what can happen.
(If you do the same thing with a non-variadic function with a visible prototype, so the compiler knows at the point of the call that the parameter is of type void*, then it will generate code to do an implicit int*-to-void* conversion. That's not the case here.)
Is this a C or a C++ question? For C++, it seems that according to 5.2.2 [expr.call] paragraph 7 there isn't any implicit conversion to void*. It seems that C99's 6.5.2.2 paragraph 6 also doesn't imply any explicit promotion of pointer types. This would mean that an explicit cast to void* is required as pointer types can have different size (at least in C++): if the layout of the different pointer types isn't identical you'd end up with undefined behavior. Can someone point out where it is guaranteed that a pointer is passed with the appropriate size when using variable argument lists?
Of course, being a C++ programmer this isn't much of a problem: just don't use functions with variable number of arguments. That's not a viable approach in C, though.
I think it might be necessary to cast. Are we certain that the size of pointers is always the same? I'm sure I read on stackoverflow recently that the size (or maybe just the alignment?) of a struct* can be different to that of a union*. This would suggest that one or both can be different from the size of a void*.
So even if the value doesn't change much, or at all, in the conversion, maybe the cast is needed to ensure the size of the pointer itself is correct.
In print, %p expects a void* so you should explicitly cast it. If you don't do so, and if you are lucky then the pointer size and pointer representation might save the day. But you should explicitly cast it to be certain - anything else is technically undefined behaviour.
int i = 1000;
void *p = &i;
int *x = static_cast<int*>(p);
int *y = reinterpret_cast<int*>(p);
which cast should be used to convert from void* to int* and why?
static_cast provided that you know (by design of your program) that the thing pointed to really is an int.
static_cast is designed to reverse any implicit conversion. You converted to void* implicitly, therefore you can (and should) convert back with static_cast if you know that you really are just reversing an earlier conversion.
With that assumption, nothing is being reinterpreted - void is an incomplete type, meaning that it has no values, so at no point are you interpreting either a stored int value "as void" or a stored "void value" as int. void* is just an ugly way of saying, "I don't know the type, but I'm going to pass the pointer on to someone else who does".
reinterpret_cast if you've omitted details that mean you might actually be reading memory using a type other than the type is was written with, and be aware that your code will have limited portability.
By the way, there are not very many good reasons for using a void* pointer in this way in C++. C-style callback interfaces can often be replaced with either a template function (for anything that resembles the standard function qsort) or a virtual interface (for anything that resembles a registered listener). If your C++ code is using some C API then of course you don't have much choice.
In current C++, you can't use reinterpret_cast like in that code. For a conversion of void* to int* you can only use static_cast (or the equivalent C-style cast).
For a conversion between different function type pointers or between different object type pointers you need to use reinterpret_cast.
In C++0x, reinterpret_cast<int*>(p) will be equivalent to static_cast<int*>(p). It's probably incorporated in one of the next WPs.
It's a misconception that reinterpret_cast<T*>(p) would interpret the bits of p as if they were representing a T*. In that case it will read the value of p using p's type, and that value is then converted to a T*. An actual type-pun that directly reads the bits of p using the representation of type T* only happens when you cast to a reference type, as in reinterpret_cast<T*&>(p).
As far as I know, all current compilers allow to reinterpret_cast from void* and behave equivalent to the corresponding static_cast, even though it is not allowed in current C++03. The amount of code broken when it's rejected will be no fun, so there is no motivation for them to forbid it.
When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used? gives some good details.
From the semantics of your problem, I'd go with reinterpret, because that's what you actually do.