I have the following static analysis report that the code is not compliant for MISRA-C rule 10.5 :
Results of ~ and << operations on operands of underlying types
unsigned char and unsigned short should immediately be cast to the
operand's underlying type
The code is :
unsigned val = ~0U;
From what i understand, the idea is to have to maximum value of an unsigned int which can also be achieved by unsigned val = UINT_MAX; from <limits.h>.
However, i would like to know if there is something wrong with this code.
To me, 0U is of type unsigned integer and has a value of 0, then operator ~ is applied which gives a result of type unsigned int with all bits set to 1 and finally it is copied to an unsigned int.
I would say that no integer promotion happens here before the operator ~ because we already have an unsigned int.
Moreover, the tool gives the same report somewhere else in the code :
uint16_t val2 = (uint16_t)(~0U); /* cast is explicit so what is wrong here ? */
I am not sure whether or not this code needs a fix for both "offending" lines.
The concept underlying type was used in the older MISRAs, nowadays deprecated and replaced with essential type categories. The definition of underlying type is the type that each of the operands in an expression would have if not for implicit type promotion.
In the expression ~0U, the type of the integer constant 0U is unsigned int. It is not a small integer type, so no integer promotion takes place upon ~. The underlying type is the same as the actual C language type, unsigned int.
unsigned val = ... assigns an unsigned int to an unsigned int. No lvalue conversion through assignment or other such implicit assignment takes place. The underlying type remains unsigned int.
Thus if your tool gives a warning about no cast to underlying type on the line unsigned val = ~0U;, your tool is simply broken.
From what i understand, the idea is to have to maximum value of an unsigned int
Very likely.
However, i would like to know if there is something wrong with this code.
No, nothing is wrong with your code. However, other MISRA rules require you to replace the default "primitive types" with types from stdint.h (or equivalent on pre-C99 compilers). So in case this is a 32 bit system, the MISRA compliant version of your code is uint32_t val.
uint16_t val2 = (uint16_t)(~0U);
This is MISRA compliant code. The underlying type of the assignment expression is uint16_t. Casting to uint16_t is correct and proper practice. Again, your tool is broken.
I am confused by the C++ conversion rules regarding unsigned-to-signed and vice versa.
I'm reading data from a socket and saving it in a std::vector<uint8_t>. I then need to read a part of it
(assuming it is ASCII data) and save it in a std::string. This is what I'm doing:
for (std::vector<uint8_t>::const_iterator it = payload.begin() + start; it < payload.begin() + end; ++it) {
store_name.push_back(*it);
}
So as you can see, *it returns a uint8_t and passes it into the push_back member function of std::string, which takes a char - thus an implicit conversion occurs. char may in fact be either signed or unsigned. I'm not sure what happens if it is signed.
I cannot wrap (no pun intended) my head around what is happening here, and whether or not it is safe.
Does store_name.push_back(*it) change the bit-pattern of *it before storing it in the std::string?
What rules exactly govern this?
I've gone through many places online explaining type-conversion rules, but it still doesn't really stick with me. Explanations will be appreciated.
EDIT: As a different way to put it - in general, what happens when we cast unsigned to signed and vice versa?
unsigned char a = 50; // Inside the range of signed char
signed char b = (signed char) a;
Is the bit pattern in b required to be the same as the bit pattern in a? Or may the bit pattern change?
Also, what about the opposite direction:
a = (unsigned char) b;
Again - does a change to the bit pattern occur? Or is it guaranteed that the underlying bit pattern stays the same, no matter how many signed-unsigned conversion we do, as long as the value is in the correct range?
And does it matter if it's an explicit cast using (cstyle cast) or static_cast<>, or if it's an implicit cast by assignment?
From implicit conversions - Numeric Conversion/Integral conversions:
To unsigned
If the destination type is unsigned, the resulting value is the
smallest unsigned value equal to the source value modulo 2n where n
is the number of bits used to represent the destination type. That is,
depending on whether the destination type is wider or narrower, signed
integers are sign-extended[footnote 1] or truncated and unsigned
integers are zero-extended or truncated respectively.
To signed
If the destination type is signed, the value does not change if the
source integer can be represented in the destination type. Otherwise
the result is implementation-defined (until C++20)the unique value of
the destination type equal to the source value modulo 2n where n is
the number of bits used to represent the destination type. (since
C++20). (Note that this is different from signed integer arithmetic
overflow, which is undefined).
So for values in range, there should be no conversion. Otherwise, I interpret it as if your machine represents values as two's complement, there is no changes in the bits for conversion to unsigned (from C++20 also to signed) and implementation defined until C++20. (I am not sure why, but I assume most compilers do not change the value, even though they are allowed to).
Regarding cstyle-cast vs static-cast: cstyle-cast performs (link)
When the C-style cast expression is encountered, the compiler
attempts to interpret it as the following cast expressions, in this
order:
a) const_cast<new_type>(expression);
b) static_cast<new_type>(expression), with extensions: pointer or
reference to a derived class is additionally allowed to be cast to
pointer or reference to unambiguous base class (and vice versa) even
if the base class is inaccessible (that is, this cast ignores the
private inheritance specifier). Same applies to casting pointer to
member to pointer to member of unambiguous non-virtual base;
c) static_cast (with extensions) followed by const_cast;
d) reinterpret_cast<new_type>(expression);
e) reinterpret_cast followed> by const_cast. The first choice that satisfies the requirements of the respective cast operator is selected, even if it cannot be compiled.
So for signed<->unsiged conversions, cstyle-cast should be the same as static_cast.
For implicit conversion (implicit conversions - Order of the conversions)
Implicit conversion sequence consists of the following, in this order:
zero or one standard conversion sequence;
zero or one user-defined conversion;
zero or one standard conversion sequence.
, where
A standard conversion sequence consists of the following, in this
order:
zero or one conversion from the following set: lvalue-to-rvalue
conversion, array-to-pointer conversion, and function-to-pointer
conversion;
zero or one numeric promotion or numeric conversion;
zero or one function pointer conversion; (since C++17) 4) zero or one
qualification adjustment.
and numeric conversion is yet again the conversion quoted on the top.
static_cast itself converts between types using a combination of implicit and user-defined conversions (link). So there should not be any difference between implicit or explicit.
Recently I encountered code that did this:
static_assert(sizeof(void*) >= sizeof(size_t));
size_t idx = get_index_to_array();
void* ptr = (void*)idx;
Essentially using a void* pointer provided by a third party library to store an index into an array to save an allocation.
Assuming that the pointer will neither be dereferenced nor freed/deleted at any point, and will be only used to cast back to the original value, is this code strictly conforming C++ (per the C++17 standard, if that matters)?
Asuming that the pointer will not get dereferenced nor freed/deleted at any point and will be only used to cast back to the original value, is this code strictly conforming C++ (per the C++17 standard, if that matters)?
It is conforming.
Since there is no compatible static cast, this explicit type conversion (colloquially called C-style cast) performs a reinterpret cast. Of this, the standard says (quoting the latest draft):
[expr.reinterpret.cast]
A value of integral type or enumeration type can be explicitly converted to a pointer.
A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.
If, as you say, this void* pointer will not be used for anything but being cast back to an int, then yes, this code is fine.
The C-style cast in (void*)idx falls back to a reinterpret_cast when all other casts fail (such as static_cast). Usually reinterpret cast is a dangerous thing, but it does come with the guarantee that casting to an intermediate type, then back to the original type, will always yield the original value. Thus, your code, under the stated constraints, is fine.
How can I know how will reinterpret cast work on GCC compiler? Is it mentioned in the documentation? May I know any reference or link if it exist?
Reading the documentation in the standard it is very explicit about different types. But for the basic pointer we have:
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 ] A value of type std::nullptr_t can be converted to an integral type; the conversion has the same meaning and validity as a conversion of (void*)0 to the integral type. [Note: A reinterpret_cast cannot be used to convert a value of any type to the type std::nullptr_t. — end note ]
For integers:
A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined. [Note: Except as described in 3.7.4.3, the result of such a conversion will not be a safely-derived pointer value. —endnote]
I have used reinterpret_cast many times with g++. In embedded programming, it's useful for mapping a struct that represents a peripheral's registers to its (fixed) address:
struct DEV_Registers
{
volatile uint32_t REGA;
volatile uint32_t REGB;
// ...
};
static DEV_Registers& DEV(*reinterpret_cast<DEV_Registers>(0x40000000));
This lets me write code like:
DEV.REGB = 0x12345678;
which does the right thing (set the register at 0x40000004 to the value 0x12345678) and is quite legible.
It's hard to tell if your question is asking for details beyond this.
Is it safe to cast pointer to int and later back to pointer again?
How about if we know if the pointer is 32 bit long and int is 32 bit long?
long* juggle(long* p) {
static_assert(sizeof(long*) == sizeof(int));
int v = reinterpret_cast<int>(p); // or if sizeof(*)==8 choose long here
do_some_math(v); // prevent compiler from optimizing
return reinterpret_cast<long*>(v);
}
int main() {
long* stuff = new long(42);
long* ffuts = juggle(stuff);
std::cout << "Is this always 42? " << *ffuts << std::endl;
}
Is this covered by the Standard?
No.
For instance, on x86-64, a pointer is 64-bit long, but int is only 32-bit long. Casting a pointer to int and back again makes the upper 32-bit of the pointer value lost.
You may use the intptr_t type in <cstdint> if you want an integer type which is guaranteed to be as long as the pointer. You could safely reinterpret_cast from a pointer to an intptr_t and back.
Yes, if... (or "Yes, but...") and no otherwise.
The standard specifies (3.7.4.3) the following:
A pointer value is a safely-derived pointer [...] if it is the result of a well-defined pointer conversion or reinterpret_cast of a safely-derived pointer value [or] the result of a reinterpret_cast of an integer representation of a safely-derived pointer value
An integer value is an integer representation of a safely-derived pointer [...] if its type is at least as large as std::intptr_t and [...] the result of a reinterpret_cast of a safely-derived pointer value [or]
the result of a valid conversion of an integer representation of a safely-derived pointer value [or] the result of an additive or bitwise operation, one of whose operands is an integer representation of a
safely-derived pointer value
A traceable pointer object is [...] an object of an integral type that is at least as large as std::intptr_t
The standard further states that implementations may be relaxed or may be strict about enforcing safely-derived pointers. Which means it is unspecified whether using or dereferencing a not-safely-derived pointer invokes undefined behavior (that's a funny thing to say!)
Which alltogether means no more and no less than "something different might work anyway, but the only safe thing is as specified above".
Therefore, if you either use std::intptr_t in the first place (the preferrable thing to do!) or if you know that the storage size of whatever integer type you use (say, long) is at least the size of std::intptr_t, then it is allowable and well-defined (i.e. "safe") to cast to your integer type and back. The standard guarantees that.
If that's not the case, the conversion from pointer to integer representation will probably (or at least possibly) lose some information, and the conversion back will not give a valid pointer. Or, it might by accident, but this is not guaranteed.
An interesting anecdote is that the C++ standard does not directly define std::intptr_t at all; it merely says "the same as 7.18 in the C standard".
The C standard, on the other hand, states "designates a signed integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer".
Which means, without the rather complicated definitions above (in particular the last bit of the first bullet point), it wouldn't be allowable to convert to/from anything but void*.
Yes and no.
The language specification explicitly states that it is safe (meaning that in the end you will get the original pointer value) as long as the size of the integral type is sufficient to store the [implementation-dependent] integral representation of the pointer.
So, in general case it is not "safe", since in general case int can easily turn out to be too small. In your specific case it though it might be safe, since your int might be sufficiently large to store your pointer.
Normally, when you need to do something like that, you should use the intptr_t/uintptr_t types, which are specifically introduced for that purpose. Unfortunately, intptr_t/uintptr_t are not the part of the current C++ standard (they are standard C99 types), but many implementations provide them nevertheless. You can always define these types yourself, of course.
In general, no; pointers may be larger than int, in which case there's no way to reconstruct the value.
If an integer type is known to be large enough, then you can; according to the Standard (5.2.10/5):
A pointer converted to an integer of sufficient size ... and back to the same pointer type will have its original value
However, in C++03, there's no standard way to tell which integer types are large enough. C++11 and C99 (and hence in practice most C++03 implementations), and also Boost.Integer, define intptr_t and uintptr_t for this purpose. Or you could define your own type and assert (preferably at compile time) that it's large enough; or, if you don't have some special reason for it to be an integer type, use void*.
Is it safe? Not really.
In most circumstances, will it work? Yes
Certainly if an int is too small to hold the full pointer value and truncates, you won't get your original pointer back (hopefully your compiler will warn you about this case, with GCC truncating conversions from pointer to integers are hard errors). A long, or uintptr_t if your library supports it, may be better choices.
Even if your integer type and pointer types are the same size, it will not necessarily work depending on your application runtime. In particular, if you're using a garbage collector in your program it might easily decide that the pointer is no longer outstanding, and when you later cast your integer back to a pointer and try to dereference it, you'll find out the object was already reaped.
Absolutely not. Doing some makes a bad assumption that the size of an int and a pointer are the same. This is almost always no the case on 64 bit platforms. If they are not the same a precision loss will occur and the final pointer value will be incorrect.
MyType* pValue = ...
int stored = (int)pValue; // Just lost the upper 4 bytes on a 64 bit platform
pValue = (MyType*)stored; // pValue is now invalid
pValue->SomeOp(); // Kaboom
No, it is not (always) safe (thus not safe in general). And it is covered by the standard.
ISO C++ 2003, 5.2.10:
A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined.
A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.
(The above emphases are mine.)
Therefore, if you know that the sizes are compatible, then the conversion is safe.
#include <iostream>
// C++03 static_assert.
#define ASSURE(cond) typedef int ASSURE[(cond) ? 1 : -1]
// Assure that the sizes are compatible.
ASSURE(sizeof (int) >= sizeof (char*));
int main() {
char c = 'A';
char *p = &c;
// If this program compiles, it is well formed.
int i = reinterpret_cast<int>(p);
p = reinterpret_cast<char*>(i);
std::cout << *p << std::endl;
}
Use uintptr_t from "stdint.h" or from "boost/stdint.h". It is guaranteed to have enough storage for a pointer.
No it is not. Even if we rule out the architecture issue, size of a pointer and an integer have differences. A pointer can be of three types in C++ : near, far, and huge. They have different sizes. And if we talk about an integer its normally of 16 or 32 bit. So casting integer into pointers and vice-verse is not safe. Utmost care has to be taken, as there very much chances of precision loss. In most of the cases an integer will be short of space to store a pointer, resulting in loss of value.
If your going to be doing any system portable casting, you need to use something like Microsofts INT_PTR/UINT_PTR, the safety after that relies on the target platforms and what you intend doing to the INT_PTR. generally for most arithmatic char* or uint_8* works better while being typesafe(ish)
To an int ? not always if you are on a 64 bit machine then int is only 4 bytes, however pointers are 8 bytes long and thus you would end up with a different pointer when you cast it back from int.
There are however ways to get around this. You can simply use an 8 byte long data type ,which would work whether or not you are on 32/64 bit system, such as unsigned long long unsigned because you don't want sign extension on 32-bit systems.
It is important to note that on Linux unsigned long will always be pointer size* so if you are targeting Linux systems you could just use that.
*According to cppreference and also tested it myself but not on all Linux and Linux like systems
If the issue is that you want to do normal math on it, probably the safest thing to do would be to cast it to a pointer to char (or better yet, * uint8_t), do your math, and then cast it back.