Why will this not dynamic_cast? - c++

I am trying to learn about some of the C++ features and coded up a little test. However, when I try to compile, I get the following error (below). Why is this happening and what is the correct way to do it? I'm trying to cast a 32 bit pointer to an 8 bit pointer and print out the contents after the conversion.
cast3.cpp:22: error: cannot dynamic_cast 'bigptr' (of type 'uint32_t*') to type 'uint8_t*' (target is not pointer or reference to class)
Code:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void castme(uint8_t small[], int size);
int main(void)
{
uint8_t *small;
uint32_t big = 0x01234567;
uint32_t *bigptr = &big;
small = dynamic_cast<uint8_t *>(bigptr); // Line 22
castme(small, sizeof(big));
return 0;
}
void castme(uint8_t small[], int size)
{
for (int i = 0; i < size; i++)
{
printf("0x%x\n", small[i]);
}
}

dynamic_cast only works on classes with virtual member functions. To cast raw pointer types between each other, you need reinterpret_cast.

You are using the wrong cast. dynamic_cast only works with polymorphic class types, as it performs RTTI lookups at runtime. You are not using polymorphic class types in your code. To simply treat one pointer type as another pointer type, you need to use reinterpret_cast instead:
small = reinterpret_cast<uint8_t *>(bigptr);

To make the code compile, you can do the following:
small = reinterpret_cast<uint8_t *>(bigptr);
but I wouldn't do that, you should probably dereference the uint32_t pointer and then cast to the type you desire - there's no point casting to a uint8_t pointer in my mind.
ie.
uint8_t small_one = *bigptr;

Use reinterpret_cast. dynamic_cast has a different purpose.

Related

uint32_t pointer to the same location as uint8_t pointer

#include <iostream>
int main(){
uint8_t memory[1024];
memory[0] = 1;
memory[1] = 1;
uint32_t *test = memory;
//is it possible to get a value for *test that would be in this example 257?
}
I want to create a uin32_t pointer to the same adress as the uint8_t pointer. Is this possible without using new(adress)? I don't want to lose the information at the adress. I know pointers are just adresses and therefor I should be able to just set the uint32_t pointer to the same adress.
This code produces an error:
invalid conversion from 'uint8_t*' to 'uint32_t*' in initialization
This would be a violation of so-called Strict Aliasing Rule, so it can not be done. Sad, but true.
Use memcpy to copy data and in many cases compilers will optimize memory copy and generate the same code as they would with cast, but in Standard-conforming way.
As already mentioned you cannot convert uint8_t * to uint32_t * due to strict aliasing rule, you can convert uint32_t * to unsigned char * though:
#include <iostream>
int main(){
uint32_t test[1024/4] = {}; // initialize it!
auto memory = reinterpret_cast<unsigned char *>( test );
memory[0] = 1;
memory[1] = 1;
std::cout << test[0] << std::endl;
}
this is not portable code due to Endianness, but at least it does not have UB.
This question completely ignores the concept of endian-ness; while your example has the lower and upper byte the same value, if the byte order is swapped it makes no difference; but in the case where it is; your number will be wrong unexpectedly.
As such, there's no portable way to use the resulting number.
You can do that with union. As mentioned above, you have to be aware of endianness of target device, but in most cases it will be little-endian. And there is also a bit of controversy about using unions in such way, but fwiw it's getting a job done and for some uses it's good enough.
#include <iostream>
int main(){
union {
uint8_t memory[1024] = {};
uint32_t test[1024/4];
};
memory[0] = 1;
memory[1] = 1;
std::cout << test[0]; // 257
}
uint32_t *test =(uint32_t*) memory;
uint32_t shows that the memory pointed by test should contain uint32_t .

C++ Type-safe detection of the offset of a structure

I'm playing a bit with the C++ syntax to figure out a generalized way to keep track of an offset within a class, sort of like offsetof, but in a type-safe way and without #defines
I know that a template class can be template-parametrized with fields, besides types and constants. So I came out with this prototype:
#include <iostream>
template <typename class_type, typename field_type>
struct offsetter
{
offsetter(const char* name, field_type class_type::*field)
: name(name)
{
fprintf(stderr, "%zu\n", field);
}
const char* const name;
};
struct some_struct
{
float avg;
int min;
int max;
struct internal
{
unsigned flag;
int x;
} test;
char* name;
};
int main()
{
offsetter<some_struct, float>("%h", &some_struct::avg);
offsetter<some_struct, int>("%h", &some_struct::min);
offsetter<some_struct, char*>("%h", &some_struct::name);
offsetter<some_struct, some_struct::internal>("x", &some_struct::test);
return 0;
}
This code is actually able to print the field offset, but I'm not really sure on what I'm doing here. Indeed it feels utterly wrong to reference field without referring to an instance (foo.*field).
But it does the job: it prints the offset. My guess is that I'm hitting on some loophole though, since for instance I can't assign size_t offset = field.
I figured out I probably want something like this:
size_t offset = (&(std::declval<class_type>().*field) - &(std::declval<class_type>()))
Which however wont' work as I can't take the address of an xvalue:
taking address of xvalue (rvalue reference)
Is there any way to do this?
AFAIK there isn't a standard way of doing this. Even the standard offsetof is defined only for standard layout types.
What you are doing is UB. You are using the wrong specifier zu. There isn't much you can do with a member pointer. You can't even do pointer arithmetics on them, you can't convert to char* nor to an integer type.
Also if your assumption is that a member pointer is just an integer representing the offset from the beginning of the structure that is false, not only in theory, but also in practice. Having multiple inheritance and virtual inheritance made sure of that.

Convert "void*" to int without warning

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.

structures and pointer arithmetic

#include <iostream>
#include <cmath>
using namespace std;
struct demo{
int one;
int two;
int three;
};
int main()
{
demo d1;
demo *dptr=&d1;
*dptr=1 ;
++dptr;
*dptr=2;
++dptr;
*dptr=3;
return 0;
}
Please explain why the above code looks logical but in fact does not work
in line 13 of code. Log error:
no match for 'operator=' in '*dptr=1'
demo d1;
demo *dptr=&d1;
*dptr=1 ;
++dptr;
dptr=2;
++dptr;
dptr=3;
dptr is a pointer pointing to a demo struct. So, *dptr = 1 is basically the same as d1 = 1;, that's not valid.
Plus, having a pointer of that type and doing ++ on that pointer applies pointer arithmetic for that type, shoving the pointer sizeof(demo), that's not what you want here. You'll need to create an int pointer by casting it, then using that pointer to read the 3 fields
int* dptr=reinterpret_cast<int*>(&d1);
Padding can still ruin your day though, however, since they're all int's you should be fine.
You need to declare your dptr as int*, not demo*.
int *dptr=&d1; // might need type cast (int*)
*dptr=1 ;

Casting Function Pointer to Integer in C++

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);
}