I need to convert "void*" to int, but compiler keeps giving me warning.
Wonder if there is a way to change the code so that compiler will not complain. This occurs a lot in the code base, especially when passing an argument to starting a new thread.
$ g++ -fpermissive te1.cc
te1.cc: In function ‘void dummy(void*)’:
te1.cc:4:15: warning: cast from ‘void*’ to ‘int’ loses precision [-fpermissive]
int x = (int)p;
^
Here is the simple code "te1.cc":
#include <stdio.h>
extern void someFunc(int);
void dummy(int type, void *p) {
if (type == 0) {
int x = (int)p;
someFunc(x);
} else if (type == 1) {
printf("%s\n", (char*)p);
}
}
int main(int argc, char *argv[]) {
void *p = (void*)5;
dummy(p);
return 0;
}
UDPATE1
I understand that I will lose precision. It's intended sometimes. What I need is to have a way to remove the warning in places I know for sure it's safe. Sorry for not making it clear earlier.
UDPATE2
Updated the code snippet to be a little less non-trivial to illustrate the point. The parameter needs to pass different type of values. I need a way to cast without generating warning.
I need to convert "void*" to int
no you don't.
I really do...
no, you need to represent a pointer as some kind of integer type which is guaranteed not to lose information.
#include <cstdio>
#include <cstdint>
#include <iostream>
#include <cstring>
#include <utility>
#include <cinttypes>
void dummy(void *p) {
std::intptr_t x = reinterpret_cast<std::intptr_t>(p);
printf("x = %" PRIiPTR "\n", x);
// ^^ see here: http://en.cppreference.com/w/cpp/types/integer
}
int main(int argc, char *argv[]) {
void *p = (void*)5;
dummy(p);
return 0;
}
ok, what I really want to do is work with 32-bit values in a standards-compliant way.
This is what std::uint32_t is for:
#include <cstdint>
#include <iostream>
void dummy(std::uint32_t x) {
std::cout << x << '\n';
}
int main(int argc, char *argv[]) {
auto x = std::uint32_t(5);
dummy(x);
return 0;
}
std::uint32_t - guaranteed to be unsigned 32 bits
std::int32_t - guaranteed to be signed 32 bits
You are probably looking for something along the lines of
int x = static_cast<int>(reinterpret_cast<std::uintptr_t>(p));
This is not strictly guaranteed to work: perhaps surprisingly, the standard guarantees that a pointer converted to a large enough integer and back to a pointer results in the same value; but doesn't provide a similar guarantee for when an integer is converted to a pointer and back to the integer. All it says about the latter case is
[expr.reinterpret.cast]/4 A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined. [ Note: It is intended to be unsurprising to those who know the addressing structure of the underlying machine. —end note ]
Hopefully, you know the addressing structure of your machine, and won't be surprised.
Related
When compiling with -Werror=address-of-packed-member taking the address of an unaligned element in a packed struct is an error, as it should. Nevertheless, there may be cases where you know it is safe to take such unaligned pointer and want to allow it for a parameter in a particular function call.
Is there any syntax that would let g++ know a function argument should accept unaligned pointers with no warning/error? I know I could disable the error/warning, but that will hide also mistakes I may have in other parts of my code.
// Example program
#include <iostream>
#include <cstring>
template<typename T> void memcpy(T* dst, T* src)
{
memcpy(dst,src,sizeof(T));
}
int main()
{
struct {
char c;
int d;
}__attribute__((packed)) v;
v.d=10;
int e;
memcpy(&e,&v.d);
std::cout<<e;
}
Results in the following error, but is perfectly valid code, because the type information is only used to obtain the size, but the pointer is cast to void* before use.
error: taking address of packed member of ‘main()::<unnamed struct>’ may result in an unaligned pointer value [-Werror=address-of-packed-member]
18 | memcpy(&e,&v.d);
I'm looking for a mechanism similar to the usage of (void)argv; to avoid error with -Werror=unused-parameter.
It turns out you can always take a pointer void* of any alignment, so the solution may be along the lines of
// Example program
#include <iostream>
#include <cstring>
template<typename T> void memcpy(T* dst, void* src)
{
memcpy(dst,src,sizeof(T));
}
int main()
{
struct {
char c;
int d;
}__attribute__((packed)) v;
v.d=10;
int e;
memcpy(&e,&v.d);
std::cout<<e;
}
which no longer gives any errors/warnings.
See the following code:
#include <iostream>
#include <stdlib.h>
using namespace std;
class ex
{
public:
int x;
int y;
double z;
ex()
{
cout<<"constructor";
}
~ex()
{
cout<<"destructor";
}
};
int main()
{
void *pt=malloc(sizeof(ex)*2);
ex *p,*p1;
p=new(pt) ex();
p1=new(pt+sizeof(ex)) ex();
p->x=4444;
p->y=3333;
p->z=65.87879898;
p1->x=55555;
p1->y=66666;
p1->z=6666.6666666;
cout<<"\nP: "<<p->x<<"\n"<<p->y<<"\n"<<p->z<<"\n";
cout<<"\np1: "<<p1->x<<"\n"<<p1->y<<"\n"<<p1->z<<"\n";
p->~ex();
p1->~ex();
free(pt);
return 0;
}
It shows warning.
warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]|
There is any way to overcome that or the code is wrong.
note:That code displays correct output.
Thank you for helping.
This line is problematic:
pt+sizeof(ex)
Since pt is a void* it's not known what the size of one element is. Some compilers will compile it as if the size were 1, which makes your code run successfully. But this is not standards compliant. Instead, do this:
p+1
That is, use the memory address which is one element (of type ex) after the first one.
Or, cast to char* so you know you're operating with elements of size 1:
static_cast<char*>(pt)+sizeof(ex)
I am pretty new to C++17 and am attempting to understand the decltype keyword and how it pairs with auto.
Below is a snippet of code that produces an unexpected result.
#include <typeinfo>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int16_t mid = 4;
auto low = mid - static_cast<int16_t>(2);
auto hi = mid + static_cast<int16_t>(2);
int16_t val;
cin >> val;
val = std::clamp(val,low,hi);
return 0;
}
Surprisingly, the compiler tells me there is a mismatch in clamp and that low and high are int. If I change auto to int16_t all is good in the world and all the types are int16_t as expected.
The question I'm posing is, why does auto cast low and hi to int when all of the types are int16_t? Is this a good use case for decltype?
Even after reading cppreference.com, I don't fully understand how decltype works, so excuse my ignorance.
The problem isn't with auto here. When you subtract two int16_t values, the result is an int. We can demonstrate it with this code here:
#include <iostream>
#include <cstdint>
using namespace std;
template<class T>
void print_type(T) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main() {
int16_t a = 10;
int16_t b = 20;
print_type(a);
print_type(b);
print_type(a - b);
return 0;
}
a and b are both short ints, but when you add or subtract them it produces a regular int. This is to help prevent overflow / and is also for backwards compatibility.
This phenomenon is called the usual arithmetic conversions. It is defined in the C and C++ standards and (roughly said) converts anything smaller than an int to an int. It converts larger types as well. Take some time and read about it, you'll need it quite often.
I have an array of unsigned integers that need to store pointers to data and functions as well as some data. In the device I am working with, the sizeof pointer is the same as sizeof unsigned int. How can I cast pointer to function into unsigned int? I know that this makes the code not portable, but it is micro controller specific. I tried this:
stackPtr[4] = reinterpret_cast<unsigned int>(task_ptr);
but it give me an error "invalid type conversion"
Casting it to void pointer and then to int is messy.
stackPtr[4] = reinterpret_cast<unsigned int>(static_cast<void *> (task_ptr));
Is there a clean way of doing it?
Edit - task_ptr is function pointer void task_ptr(void)
Love Barmar's answer, takes my portability shortcoming away. Also array of void pointer actually makes more sense then Unsigned Ints. Thank you Barmar and isaach1000.
EDIT 2: Got it, my compiler is thinking large memory model so it is using 32 bit pointers not 16 bit that I was expecting (small micros with 17K total memory).
A C-style cast can fit an octogonal peg into a trapezoidal hole, so I would say that given your extremely specific target hardware and requirements, I would use that cast, possibly wrapped into a template for greater clarity.
Alternately, the double cast to void* and then int does have the advantage of making the code stand out like a sore thumb so your future maintainers know something's going on and can pay special attention.
EDIT for comment:
It appears your compiler may have a bug. The following code compiles on g++ 4.5:
#include <iostream>
int f()
{
return 0;
}
int main()
{
int value = (int)&f;
std::cout << value << std::endl;
}
EDIT2:
You may also wish to consider using the intptr_t type instead of int. It's an integral type large enough to hold a pointer.
In C++ a pointer can be converted to a value of an integral type large enough to hold it. The conditionally-supported type std::intptr_t is defined such that you can convert a void* to intptr_t and back to get the original value. If void* has a size equal to or larger than function pointers on your platform then you can do the conversion in the following way.
#include <cstdint>
#include <cassert>
void foo() {}
int main() {
void (*a)() = &foo;
std::intptr_t b = reinterpret_cast<std::intptr_t>(a);
void (*c)() = reinterpret_cast<void(*)()>(b);
assert(a==c);
}
This is ansi compliant:
int MyFunc(void* p)
{
return 1;
}
int main()
{
int arr[2];
int (*foo)(int*);
arr[0] = (int)(MyFunc);
foo = (int (*)(int*))(arr[0]);
arr[1] = (*foo)(NULL);
}
#include <vector>
#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc, const char *argv[])
{
vector<bool> a;
a.push_back(false);
int t=a[0];
printf("%d %d\n",a[0],t);
return 0;
}
This code give output "5511088 1". I thought it would be "0 0".
Anyone know why is it?
The %d format specifier is for arguments the size of integers, therefore the printf function is expecting two arguments both the size of an int. However, you're providing it with one argument that isn't an int, but rather a special object returned by vector<bool> that is convertible to bool.
This is basically causing the printf function to treat random bytes from the stack as part of the values, while in fact they aren't.
The solution is to cast the first argument to an int:
printf("%d %d\n", static_cast<int>(a[0]), t);
An even better solution would be to prefer streams over printf if at all possible, because unlike printf they are type-safe which makes it impossible for this kind of situation to happen:
cout << a[0] << " " << t << endl;
And if you're looking for a type-safe alternative for printf-like formatting, consider using the Boost Format library.
%d format specifier is for int type. So, try -
cout << a[0] << "\t" << t << endl;
The key to the answer is that vector isn't really a vector of bools. It's really a vector of proxy objects, which are translatable into ints & bools. This allows each bool to be stored as a single bit, for greater space efficiency (at the cost of speed efficiency), but causes a number of problems like the one seen here. This requirement was voted into the C++ Standard in a rash moment, and I believe most committee members now believe it was a mistake, but it's in the Standard and we're kind-of stuck with it.
The problem is triggered by the specialization for bool of vectors.
The Standard Library defines a specialization of the vector template for bool. The description of this specialization indicates that the implementation should pack the elements so that every bool only uses one bit of memory. This is widely considered a mistake.
Basically std::bool use 1 bit instead of 1 byte, so you face undefined behavior regarding printf.
If you are really willing to use printf, you can solve this issue by defining std::bool as char and print it as integer %d (implicit conversion, 1 for true and 0 for false).
#include <vector>
#include <iostream>
#include <stdio.h>
#define bool char // solved
using namespace std;
int main(int argc, const char *argv[])
{
vector<bool> a;
a.push_back(false);
int t = a[0];
printf("%d %d\n", a[0], t);
return 0;
}