Difference between static_cast<char*> and (char*) - c++

this is my first question :)
I have one pile file, and I have open it like shown below ;
ifstream in ( filename, ios :: binary | ios :: in )
Then, I wish hold 2 byte data in unsigned int hold ;
unsigned int hold;
in . read(static_cast<char *>(&hold), 2);
It seems correct to me. However, when I compile it with
g++ -ansi -pedantic-errors -Werror - -Wall -o main main.cpp
Compiler emits error
error: invalid static_cast from type ‘unsigned int*’ to type ‘char*’
Actually, I have solved this problem by changing static_cast with ( char*), that is
unsigned int hold;
in . read((char*)(&hold), 2);
My questions are :
What is the difference(s) between static_cast<char*> and (char*) ?
I am not sure whether using (char*) is a safer or not. If you have enough knowledge, can you inform me about that topic ?
NOTE : If you have better idea, please help me so that I can improve my question?

static_cast is a safer cast than the implicit C style cast. If you try to cast an entity which is not compatible to another, then static_cast gives you an compilation time error unlike the implicit c-style cast.
static_cast gives you an error here because what you are trying to say is take an int and try to fit it in a char, which is not possible. int needs more memory than what char occupies and the conversion cannot be done in a safe manner.
If you still want to acheive this,You can use reinterpret_cast, It allows you to typecast two completely different data types, but it is not safe.
The only guarantee you get with reinterpret_cast is that if you cast the result back to the original type, you will get the same value, But no other safety guarantees.

first - you can easily search for _cast and find any c++ cast. Searching c-style casts is a lot harder.
second - if you use c++ casts, you need to choose the correct one. In your case, it is reinterpret_cast.
The c-style cast does everything.
you can also check here: http://www.cplusplus.com/doc/tutorial/typecasting/ for the differences of the different c++ casts. I strongly recommend only to use c++ casts. This way you can easily find & check them later and you are forced to think about what you are actually doing there. This improves code quality!

You should have used reinterpret_cast<char *> instead of static_cast<char *>, because the data types are not related: you can convert between a pointer to a subclass to a superclass for instance, or between int and long, or between void * and any pointer, but unsigned int * to char * isn't "safe" and thus you cannot do it with static_cast.
The difference is that in C++ you have various types of casts:
static_cast which is for "safe" conversions;
reinterpret_cast which is for "unsafe" conversions;
const_cast which is for removing a const attribute;
dynamic_cast which is for downcasting (casting a pointer/reference from a superclass to a subclass).
The C-style cast (char *)x can mean all of these above, so it is not as clear as the C++ casts. Furthermore, it is easy to grep for a C++-style cast (just grep for _cast), but it's quite hard to search for all C-style casts.

The static_cast is illegal here; you're casting between unrelated
pointer types. The solution to get it to compile would be to use
reinterpret_cast (which is what (char*) resolves to in this case).
Which, of course, tells you that the code isn't portable, and in fact,
unless you're doing some very low level work, probably won't work
correctly in all cases.
In this case, of course, you're reading raw data, and claiming it's an
unsigned int. Which it isn't; what read inputs is raw data, which you
still have to manually convert to whatever you need, according to the
format used when writing the file. (There is no such thing as
unformatted data. Just data with an undocumented, unspecified, or
unknown format. The “unformatted” input and output in
iostream are designed to read and write char buffers which you format
manually. The need for reinterpret_cast here is a definite warning
that something is wrong with your code. (There are exceptions, of
course, but they're few and far between.)

You will typically get these errors during binary file I/O using ifstream or ofstream or fstream. Problem is that these streams have methods that take const char* while what you have is array of some other type. You want to write your array as binary bits in to the file.
The traditional way of doing this is using old-style cast (char*) which basically just says that whatever pointer I've treat it as (char*). The old style casts are discouraged by pedantic/strict mode. To get rid of those warnings, the C++11 equivalent is reinterpret_cast<const char*>.
I would say, if you are doing binary file I/O then you already know things may or may not be portable depending on how you save the file in one OS and read in another OS. That's whole another issue, however, don't get scared by reinterpret_cast<const char*> because that's what you have to do if you want to write bytes to file.

Related

Can wrapping a type conversion in a static_cast ever hurt?

I'm updating some old code and I get hundreds of warnings along the lines of warning C4244: '+=': conversion from 'std::streamsize' to 'unsigned long', possible loss of data in Visual Studio.
The project compiles and runs fine when just ignoring the warnings, but I want to remove them and put a static_cast<unsigned long>() function around each. Considering the code runs fine now, could this potentially be harmful?
Yes, static_cast can hurt, as it will tell the compiler to shut up, as you know what you are doing. The question is whether you actually know what you are doing?
Obviously, casting to a smaller type can result in an unexpected result if the stored data exceeds the smaller types size. Use a static_cast if you know for sure, that this case won't ever happen or that you expect a truncated value. If not, keep the warning until you have properly designed your code.
The project compiles and runs fine when just ignoring the warnings
To start with, never ignore warnings. Think over what your code actually does instead.
Considering the code runs fine now, could this potentially be harmful?
Regarding your particular case, a static_cast<unsigned long> from std::streamsize will be harmful.
As the reference documentation of std::streamsize says, it's intentionally a signed type:
The type std::streamsize is a signed integral type used to represent the number of characters transferred in an I/O operation or the size of an I/O buffer. It is used as a signed counterpart of std::size_t, similar to the POSIX type ssize_t.
Static casting in that case actually means loss of semantics.
The idea is that conversions allowed by static_cast are somewhat less
likely to lead to errors than those that require reinterpret_cast. In
principle, it is possible to use the result of a static_cast without
casting it back to its original type, whereas you should always cast
the result of a reinterpret_cast back to its original type before
using it to ensure portability.
from Bjarne Stroustrup's C++ Style and Technique FAQ
Be careful with consts. static_cast doesn't cast away const.
In general, I think it would be better to rewrite your code instead of "casting every problem away" in hope that everything goes well.

MISRA C++ 2008 Rule 5-2-7 violation: An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly

In the following example:
void bad_function()
{
char_t * ptr = 0;
// MISRA doesn't complains here, it allows cast of char* to void* pointer
void* p2 = ptr;
// the following 2 MISRA violations are reported in each of the casts bellow (two per code line)
// (1) Event misra_violation: [Required] MISRA C++-2008 Rule 5-2-7 violation: An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly
// (1) Event misra_violation: [Required] MISRA C++-2008 Rule 5-2-8 violation: An object with integer type or pointer to void type shall not be converted to an object with pointer type
ptr = (char_t*) (p2);
ptr = static_cast<char_t*> (p2);
ptr = reinterpret_cast<char_t*> (p2);
}
MISRA 5-2-8 and 5-2-7 violations are reported.
How I can remove this violation ?
I need someone experienced with C++ static analysis to help me. I am hitting my head with this stupid rules from few days.
According to MISRA C++ standard (MISRA-Cpp-2008.pdf: Rule 5-2-7 (required): An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly.
Ok but we have a lot of code which for example needs to convert address to char* and then to use it with std::ifstream, which read(char* buffer, int length) function requires to type cast the address to (char_t*). So how according to MISRA guys someone can program in C++ and not using at all any casts? The standard doesn't say HOW pointer conversion then must be done.
In my production code my problems are in file reading operations using read with std::ifstream from files in predefined data structures:
if (file.read((char_t*)&info, (int32_t)sizeof(INFO)).gcount() != (int32_t)sizeof(INFO)
{
LOG("ERROR: Couldn't read the file info header\n");
res = GENERAL_FAILURE;
}
How is supposed to do it according to MISRA?
So are there any solutions at all?
EDIT: Peter and Q.Q. answers are both correct, it seems that MISRA really wants to do everything without any casts which is hard to be done if the project is in the final stage. Therea are two options:
1 - document the MISRA deviations one by one and explain why casts are Ok, explain how this has been tested (Q.Q. suggestion)
2 - use byte array from char type for file.read(), then after safely reading the file content cast the byte array to the headers content, this must be done for each member one by one because if you cast char* to int32_t this is again Rule 5-2-7 violation. Sometimes it is too much work.
The basic reason for the MISRA rule is that converting any pointer/address to any non-void pointer allows using that address as if it is a different object than it actually is. The compiler would complain about an implicit conversion in those cases. Using a typecast (or C++ _cast operators) essentially stops the compile complaining and - in too many circumstances to count - dereferencing that pointer gives undefined behaviour.
In other words, by forcing a type conversion, you are introducing potential undefined behaviour, and turning off all possibility of the compiler alerting you to the possibility. MISRA think that is a bad idea .... not withstanding the fact that a lot of programmers who think in terms of ease of coding think it is a good idea in some cases.
You have to realise that the philosophy of MISRA checks is less concerned about ease of programming than typical programmers, and more concerned about preventing circumstances where undefined (or implementation defined or unspecified, etc) behaviours get past all checks, and result in code "in the wild" that can cause harm.
The thing is, in your actual use case, you are relying on file.read() correctly populating the (presumably) data structure named info.
if (file.read((char_t*)&info, (int32_t)sizeof(INFO)).gcount() != (int32_t)sizeof(INFO)
{
LOG("ERROR: Couldn't read the file info header\n");
res = GENERAL_FAILURE;
}
What you need to do is work a bit harder to provide valid code that will pass the MISRA checker. Something like
std::streamsize size_to_read = whatever();
std::vector<char> buffer(size_to_read);
if (file.read(&buffer[0], size_to_read) == size_to_read)
{
// use some rules to interpret contents of buffer (i.e. a protocol) and populate info
// generally these rules will check that the data is in a valid form
// but not rely on doing any pointer type conversions
}
else
{
LOG("ERROR: Couldn't read the file info header\n");
res = GENERAL_FAILURE;
}
Yes, I realise it is more work than simply using a type conversion, and allowing binary saves and reads of structs. But them's the breaks. Apart from getting past the MISRA checker, this approach has other advantages if you do it right, such as the file format being completely independent of what compiler is used to build your code. Your code depends on implementation-defined quantities (the layout of members in a struct, the results of sizeof) so your code - if built with compiler A - may be unable to read a file generated by code built with compiler B. And one of the common themes of MISRA requirements is reducing or eliminated any code with behaviour that may be sensitive to implementation-defined quantities.
Note: you are also passing char_t * to std::istream::read() as first argument and an int32_t as the second argument. Both are actually incorrect. The actual arguments are of type char * and std::streamsize (which may be, but is not required to be an int32_t).
Converting unrelated pointers to char* is not a good practice.
But, if you have a large legacy codebase doing this frequently, you can suppress rules by adding special comments.
fread is a perfectly good C++ function for file input and it uses void*, which MISRA allows.
It also is good at reading binary data, unlike fstream which processes all data through localized character conversion logic (this is the "facet" on an iostream, which is configurable, but the Standard doesn't define any portable way to achieve a no-op conversion).
The C-style of fopen/fclose is unfortunate in a C++ program, since you might forget to cleanup your files. Luckily we have this std::unique_ptr which can add RAII functionality to an arbitrary pointer type. Use std::unique_ptr<FILE*, decltype(&fclose)> and have fast exception-safe binary file I/O in C++.
NB: A common misconception is that std::ios::binary gives binary file I/O. It does not. All it affects are newline conversion and (on some systems) end-of-file marker processing, but there is no effect on facet-driven character conversion.

Is there a gcc flag to allow C-style implicit pointer conversions in C++?

I'm drowning in the sea of casts between char* and unsigned char*, it's just ridiculous. There has to be some way around this.
Yes -fpermissive will allow this
No. C++ pointers are more strongly typed than C's. You are required to cast between pointer types outside of upcasting in C++ which can happen implicitly. What you want is intentionally difficult in C++ to discourage people from doing so.
C allows these potentially unsafe conversions to occur silently, but if you enable warnings in gcc, the issues will be brought to your attention.
On another note: having a char * point to an unsigned char is well defined behavior, though could be error prone in the long run depending on how the memory is used.

Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)

I need to work on a project that was written in msvcpp6.0sp6
I DIDN'T write the project. I know very little about its inner works. I DO know it WAS POSSIBLE to build it in the past.
while trying to build this project that was built successfuly in the past(not by me)
I get the error:
Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)
for example:
error C2664: 'strncpy' : cannot convert parameter 2 from 'const unsigned short *' to 'const char *'
error C2664: 'void __cdecl CString::Format(const unsigned short *,...)' : cannot convert parameter 1
for a few dozen implicit conversions. I mustn't change the code. how can I force the complier to accept the implicit convertions?
I mustn't change the code. how can I force the complier to accept the
implicit convertions?
Quite likely you need to get the same compiler that was used for the code in the first place, and use that.
If my guess (in a comment on unwind's answer) is correct about that unsigned short* error then it's simply not possible to compile this code in Unicode mode, because the source is insufficiently portable. Suppressing the error for the conversion, even if it's possible via some compiler setting, will just result in code that compiles but doesn't work.
I'd expect that also to imply that the old dll probably isn't compatible with the rest of your current code, but if you've been using it up to now then either I'm wrong about the reason, or else you've got away with it somehow.
That sounds crazy.
The use of unsigned short * with string-handling functions like strncpy() initially seems to make no sense at all. On second thought though, it makes me wonder if there is some kind of "wide character" configuration that is failing. If strncpy() was "re-targeted" by the compiler to work on 16-bit characters, having it expect unsigned short * makes sense and would explain why the code passes it such. At least "kind of" explain, it's still odd.
You can't. There are no such implicit conversions defined by the C++ language.
Visual C++ 6.0 was a law unto itself; by implementing something that merely looked a bit like the C++ language, it may have accepted this invalid code.
C++ is a typesafe language. But it allows you to tell the compiler to "shut up" by the evil known as casting.
Casting from integers to enums is often a necessary "evil" cast, for example, you cannot loop through enums where you have, say, a restricted number of values for which you have given enumerations. Therefore you have to use an integer and cast them to enums for this purpose.
Sometimes you do need to cast data structors to const char * rather than const void * just so you can perform pointer arithmetic. However for the purpose of strcpy, it is difficult to see why you want to cast in unsigned shorts. If these are wide characters (and the old compiler did not know of wchar_t) then it may be "safe" to cast it to const wchar_t * and use it in a wide-string copy. You could also use C++ strings, i.e. std::string and std::wstring.
If you really do not wish to update the source code for ISO compliance then your best bet is to use the original VC++ 6.0 compiler for your legacy code. Not least because even though you know this code to work, if it were compiled with a different compiler it will be different code and may no longer work. Any undefined or implementation defined compiler behaviour either exploited or used inadvertently could cause problems if a different compiler is used.
If you have an MSDN subscription, you can download all previous versions of VC++ for this purpose.

static_cast wchar_t* to int* or short* - why is it illegal?

In both Microsoft VC2005 and g++ compilers, the following results in an error:
On win32 VC2005: sizeof(wchar_t) is 2
wchar_t *foo = 0;
static_cast<unsigned short *>(foo);
Results in
error C2440: 'static_cast' : cannot convert from 'wchar_t *' to 'unsigned short *' ...
On Mac OS X or Linux g++: sizeof(wchar_t) is 4
wchar_t *foo = 0;
static_cast<unsigned int *>(foo);
Results in
error: invalid static_cast from type 'wchar_t*' to type 'unsigned int*'
Of course, I can always use reinterpret_cast. However, I would like to understand why it is deemed illegal by the compiler to static_cast to the appropriate integer type. I'm sure there is a good reason...
You cannot cast between unrelated pointer types. The size of the type pointed to is irrelevant. Consider the case where the types have different alignment requirements, allowing a cast like this could generate illegal code on some processesors. It is also possible for pointers to different types to have differrent sizes. This could result in the pointer you obtain being invalid and or pointing at an entirely different location. Reinterpret_cast is one of the escape hatches you hacve if you know for your program compiler arch and os you can get away with it.
As with char, the signedness of wchar_t is not defined by the standard. Put this together with the possibility of non-2's complement integers, and for for a wchar_t value c,
*reinterpret_cast<unsigned short *>(&c)
may not equal:
static_cast<unsigned short>(c)
In the second case, on implementations where wchar_t is a sign+magnitude or 1's complement type, any negative value of c is converted to unsigned using modulo 2^N, which changes the bits. In the former case the bit pattern is picked up and used as-is (if it works at all).
Now, if the results are different, then there's no realistic way for the implementation to provide a static_cast between the pointer types. What could it do, set a flag on the unsigned short* pointer, saying "by the way, when you load from this, you have to also do a sign conversion", and then check this flag on all unsigned short loads?
That's why it's not, in general, safe to cast between pointers to distinct integer types, and I believe this unsafety is why there is no conversion via static_cast between them.
If the type you're casting to happens to be the so-called "underlying type" of wchar_t, then the resulting code would almost certainly be OK for the implementation, but would not be portable. So the standard doesn't offer a special case allowing you a static_cast just for that type, presumably because it would conceal errors in portable code. If you know reinterpret_cast is safe, then you can just use it. Admittedly, it would be nice to have a straightforward way of asserting at compile time that it is safe, but as far as the standard is concerned you should design around it, since the implementation is not required even to dereference a reinterpret_casted pointer without crashing.
By spec using of static_cast restricted by narrowable types, eg: std::ostream& to std::ofstream&. In fact wchar_t is just extension but widely used.
Your case (if you really need it) should be fixed by reinterpret_cast
By the way MSVC++ has an option - either treat wchar_t as macro (short) or as stand-alone datatype.
Pointers are not magic "no limitations, anything goes" tools.
They are, by the language specification actually very constrained. They do not allow you to bypass the type system or the rest of the C++ language, which is what you're trying to do.
You are trying to tell the compiler to "pretend that the wchar_t you stored at this address earlier is actually an int. Now read it."
That does not make sense. The object stored at that address is a wchar_t, and nothing else. You are working in a statically typed language, which means that every object has one, and juts one, type.
If you're willing to wander into implementation-defined behavior-land, you can use a reinterpret_cast to tell the compiler to just pretend it's ok, and interpret the result as it sees fit. But then the result is not specified by the standard, but by the implementation.
Without that cast, the operation is meaningless. A wchar_t is not an int or a short.