Casting a vector of arrays

Started by
20 comments, last by SmkViper 8 years, 4 months ago

Hi everyone.

I 'got itno something strange in the following code:


class SomeClass {
public:
using byte = unsigned char;
void loadBuffer(std::string fileName);

private:
std::vector<std::array<byte, 100>> buffer;
}

In this simple class i declared a vector of arrays. This is because i want to read the file in blocks of 100 bytes. I know that there will always be complete 100 bytes blocks.

I tried to read the file this way:


void loadBuffer(...)
{
...
for (i = 0; i < blocks; i++)
    {
        buffer.push_back(std::array<byte, 100> {});
        file.read(static_cast<char *>(&mRom[i][0]), 100);
    }
...
}

but this gives me an error when trying to compile. It says something about invalid static cast from std::array... aka{unsigned char *} to char*.

I thought static_cast was supposed to help in this situations.

After some tweaking i found that old C fasion cast actually works:


file.read((char*)&mRom[i][0], 100);

I also discovered that reinterpret_cast works too.

I know that reinterpret_cast should be used the least possible and old-style C cast should not be used anymore.

Can anyone explain me what's going on?

Advertisement

but this gives me an error when trying to compile. It says something about invalid static cast from std::array... aka{unsigned char *} to char*.


Always copy and paste complete error messages. Never "something" an error message.

That said, unsigned char and char are distinct types. So are pointers to these types. You need to be more exact what you cast to what.

Edit: You need reinterpret_cast to change the pointer types.

Bonus tip:


buffer.emplace_back();
file.read(reinterpret_cast<char*>(mRom.back().data()), 100);
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.


Always copy and paste complete error messages. Never "something" an error message.

Sorry. The message is not in English, that's why i didn't write the complete message. Anyway, i thought that by reading the code, the error message would be clear. I guess i will stick with reinterpret_cast.

Thanks for the tip Khatharr

Casts in general (and reinterpret_cast in particular) are generally an indication that something is wrong with your code.

If your read function reads chars, why are you trying to read in unsigned chars?

Not knowing what you're using to read, this kind of looks to me like you may be reading a file in text-mode but expecting the data to be binary.

Guessing it's ifstream. http://www.cplusplus.com/reference/istream/istream/read/

Casting around file data isn't really unusual. If he wants bytes (or anything else that's not char) then a cast or conversion is sort of required at some point.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

I tried to read the file this way:


file.read(static_cast<char *>(&mRom[i][0]), 100);
but this gives me an error when trying to compile. It says something about invalid static cast from std::array... aka{unsigned char *} to char*.

I thought static_cast was supposed to help in this situations.

static_cast is for if there is a valid cast. You can static_cast an int to a float because somewhere out there there is a built-in casting function that allows conversions between the two. You can't static_cast a int* to a float*, because you are trying to get a pointer to a location the compiler knows isn't actually a float.

If there is no proper valid casting between two objects, you can forcibly tell the compiler to cast them anyway. This is telling the compiler, "Trust me, I know what I'm doing, I assume all responsibility for the consequences of this action.". This is what const_cast and reinterpret_cast do. It's saying to the compiler, "ignore your usual safeguards, I know better than you", and sometimes that's true. smile.png

I know that reinterpret_cast should be used the least possible and old-style C cast should not be used anymore.

Yes, that's correct. As much as possible, you want to use the compiler safeguards; but occasionally, you need to explicitly disable the usual safeguard for a specific piece of code. That's what reinterpret_cast does. You should use reinterpret_cast as little as possible. You should use new and delete as little as possible. Occasionally (rarely, but still occasionally), you need to use them.

Can anyone explain me what's going on?

The compiler told you there is no valid cast (or rather, it said your attempted cast was "invalid").

Why is it invalid? Because you are trying to cast a unsigned char* to a char*, and there is no built-in casting function for that. You can define a global one yourself (definitely not recommended), or you can make your arrays hold chars instead of unsigned chars (if acceptable to you).
Other than that, if you are reading a binary file, a reinterpret_cast is the correct choice, because in this situation you do want the cast despite there being no valid casting route, since you just want to write binary data to that location in memory regardless of what variable type is actually there.

By standard of c++, unsigned char and char do not differ. Without signed/unsigned keyword present, the char is implied to be unsigned one, as opposed to other integer numeric types - short/int/long which imply to be signed if keyword is not present.

I know that reinterpret_cast should be used the least possible and old-style C cast should not be used anymore.

Why old style of Some* p=(Some*)b should not be used anymore?

Retyping pointers is perfectly valid if you do not blow actual real compatibility.

By standard of c++, unsigned char and char do not differ. Without signed/unsigned keyword present, the char is implied to be unsigned one


I don't know what C++ standard you use, but it's not true in C++11, which says at http://en.cppreference.com/w/cpp/language/types

signed char - type for signed character representation.
unsigned char - type for unsigned character representation. Also used to inspect object representations (raw memory).
char - type for character representation which can be most efficiently processed on the target system (has the same representation and alignment as either signed char or unsigned char, but is always a distinct type). Multibyte characters strings use this type to represent code units. The character types are large enough to represent 256 different values (in order to be suitable for storing UTF-8 encoded data) (since C++14)


I don't know what C++ standard you use, but it's not true in C++11, which says at http://en.cppreference.com/w/cpp/language/types

I wouldn't say it's not true. char is still implied to be unsigned, but it is a distinct type from unsigned char for compiler.

If you perform numeric operations with char, it is gonna result to same value as if with unsigned char. Also if you compare char and unsigned char memory bits, they are gonna match for every value. They are just considered distinct types, so "unsigned char" in c++ code is just a water for compilation mill.

This topic is closed to new replies.

Advertisement