I have the following bit of code (nsections is defined as an int):
pipe_def.p_atamb = new double[pipe_def.nsections+1];
I get this warning:
Arithmetic overflow: Using operator '+' on a 4 byte value and then
casting the result to a 8 byte value. Cast the value to the wider type
before calling operator '+' to avoid overflow (io.2).
What type should x be in new double array(x) – int or int64? (I thought int.)
What type should x be in new double[x] ? int or int64? I thought int.
It should be (or will anyway be converted to) std::size_t.
cppreference
If type is an array type, all dimensions other than the first must be specified as ... type std::size_t (since C++14) ... [or] ... any expression convertible to std::size_t (since C++14)
Standard: [expr.new]/8
If the expression in a noptr-new-declarator is present, it is implicitly converted to std::size_t.
The count (dimension) argument for the new[] operator is of size_t type, not int. On your platform (which appears to be MSVC, targeting 64-bit architecture), that size_t type is an unsigned long long (8 bytes). Hence the warning.
You can silence this warning by casting either of the operands of the addition:
pipe_def.p_atamb = new double[static_cast<size_t>(pipe_def.nsections) + 1];
Or, if you are compiling to the C++23 Standard, you can use the integer literal suffix for the size_t type on the constant:
pipe_def.p_atamb = new double[pipe_def.nsections + 1zU];
(Prior to C++23, you could use the uLL suffix but that will become platform-dependent, because the size_t type for 32-bit builds is only a 4-byte unsigned long.)
Related
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.
Compiling some test code in avr-gcc for an 8-bit micro-controller, the line
const uint32_t N = 65537;
uint8_t values[N];
I got the following compilation warning (by default should be an error, really)
warning: conversion from 'long unsigned int' to 'unsigned int' changes value from '65537' to '1' [-Woverflow]
uint8_t values[N];
Note that when compiling for this target, sizeof(int) is 2.
So it seems that, at an array size cannot exceed the size of an unsigned int.
Am I correct? Is this GCC-specific or is it part of some C or C++ standard?
Before somebody remarks that an 8-bit microcontroller generally does not have enough memory for an array so large, let me just anticipate saying that this is beside the point.
size_t is considered as the type to use, despite not being formally ratified by either the C or C++ standards.
The rationale for this is that the sizeof(values) will be that type (that is mandatated by the C and C++ standards), and the number of elements will be necessarily not greater than this since sizeof for an object is at least 1.
So it seems that, at an array size cannot exceed the size of an
unsigned int.
That seems to be the case in your particular C[++] implementation.
Am I correct? Is this gcc-specific or is it part of some C or C++
standard?
It is not a characteristic of GCC in general, nor is it specified by either the C or C++ standard. It is a characteristic of your particular implementation: a version of GCC for your specific computing platform.
The C standard requires the expression designating the number of elements of an array to have an integer type, but it does not specify a particular one. I do think it's strange that your GCC seems to claim it's giving you an array with a different number of elements than you specified. I don't think that conforms to the standard, and I don't think it makes much sense as an extension. I would prefer to see it reject the code instead.
I'll dissect the issue with the rules in the "incorrekt and incomplet" ISO CPP standard draft n4659. Emphasis is added by me.
11.3.4 defines array declarations. Paragraph one contains
If the constant-expression [between the square brackets] (8.20) is present, it shall be a converted constant expression of type std::size_t [...].
std::size_t is from <cstddef>and defined as
[...] an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object.
Since it is imported via the C standard library headers the C standard is relevant for the properties of size_t. The ISO C draft N2176 prescribes in 7.20.3 the "minimal maximums", if you want, of integer types. For size_t that maximum is 65535. In other words, a 16 bit size_t is entirely conformant.
A "converted constant expression" is defined in 8.20/4:
A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only [any of 10 distinct conversions, one of which concerns integers (par. 4.7):]
— integral conversions (7.8) other than narrowing conversions (11.6.4)
An integral conversion (as opposed to a promotion which changes the type to equivalent or larger types) is defined as follows (7.8/3):
A prvalue of an integer type can be converted to a prvalue of another integer type.
7.8/5 then excludes the integral promotions from the integral conversions. This means that the conversions are usually narrowing type changes.
Narrowing conversions (which, as you'll remember, are excluded from the list of allowed conversions in converted constant expressions used for array sizes) are defined in the context of list-initialization, 11.6.4, par. 7
A narrowing conversion is an implicit conversion
[...]
7.31 — from an integer type [...] to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.
This is effectively saying that the effective array size must be the constant value at display, which is an entirely reasonable requirement for avoiding surprises.
Now let's cobble it all together. The working hypothesis is that std::size_t is a 16 bit unsigned integer type with a value range of 0..65535. The integer literal 65537 is not representable in the system's 16 bit unsigned int and thus has type long. Therefore it will undergo an integer conversion. This will be a narrowing conversion because the value is not representable in the 16 bit size_t2, so that the exception condition in 11.6.4/7.3, "value fits anyway", does not apply.
So what does this mean?
11.6.4/3.11 is the catch-all rule for the failure to produce an initializer value from an item in an intializer list. Because the initializer-list rules are used for array sizes, we can assume that the catch-all for conversion failure applies to the array size constant:
(3.11) — Otherwise, the program is ill-formed.
A conformant compiler is required to produce a diagnostic, which it does. Case closed.
1 Yes, they sub-divide paragraphs.
2 Converting an integer value of 65537 (in whatever type can hold the number — here probably a `long) to a 16 bit unsigned integer is a defined operation. 7.8/2 details:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source
integer (modulo 2n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s
complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is
no truncation). —end note ]
The binary representation of 65537 is 1_0000_0000_0000_0001, i.e. only the least significant bit of the lower 16 bits is set. The conversion to a 16 bit unsigned value (which circumstantial evidence indicates size_t is) computes the [expression value] modulo 2^16, i.e. simply takes the lower 16 bits. This results in the value of 1 mentioned in the compiler diagnostics.
In your implementation size_t is defined as unsigned int and uint32_t is defined as a long unsigned int. When you create a C array the argument for the array size gets implicitly converted to size_t by the compiler.
This is why you're getting a warning. You're specifying the array size argument with an uint32_t that gets converted to size_t and these types don't match.
This is probably not what you want. Use size_t instead.
The value returned by sizeof will be of type size_t.
It is generally used as the number of elements in an array, because it will be of sufficient size. size_t is always unsigned but it is implementation-defined which type this is. Lastly, it is implementation-defined whether the implementation can support objects of even SIZE_MAX bytes... or even close to it.
[This answer was written when the question was tagged with C and C++. I have not yet re-examined it in light of OP’s revelation they are using C++ rather than C.]
size_t is the type the C standard designates for working with object sizes. However, it is not a cure-all for getting sizes correct.
size_t should be defined in the <stddef.h> header (and also in other headers).
The C standard does not require that expressions for array sizes, when specified in declarations, have the type size_t, nor does it require that they fit in a size_t. It is not specified what a C implementation ought to do when it cannot satisfy a request for an array size, especially for variable length arrays.
In your code:
const uint32_t N = 65537;
uint8_t values[N];
values is declared as a variable length array. (Although we can see the value of N could easily be known at compile time, it does not fit C’s definition of a constant expression, so uint8_t values[N]; qualifies as a declaration of a variable length array.) As you observed, GCC warns you that the 32-bit unsigned integer N is narrowed to a 16-bit unsigned integer. This warning is not required by the C standard; it is a courtesy provided by the compiler. More than that, the conversion is not required at all—since the C standard does not specify the type for an array dimension, the compiler could accept any integer expression here. So the fact that it has inserted an implicit conversion to the type it needs for array dimensions and warned you about it is a feature of the compiler, not of the C standard.
Consider what would happen if you wrote:
size_t N = 65537;
uint8_t values[N];
Now there would be no warning in uint8_t values[N];, as a 16-bit integer (the width of size_t in your C implementation) is being used where a 16-bit integer is needed. However, in this case, your compiler likely warns in size_t N = 65537;, since 65537 will have a 32-bit integer type, and a narrowing conversion is performed during the initialization of N.
However, the fact that you are using a variable length array suggests you may be computing array sizes at run-time, and this is only a simplified example. Possibly your actual code does not use constant sizes like this; it may calculate sizes during execution. For example, you might use:
size_t N = NumberOfGroups * ElementsPerGroup + Header;
In this case, there is a possibility that the wrong result will be calculated. If the variables all have type size_t, the result may easily wrap (effectively overflow the limits of the size_t type). In this case, the compiler will not give you any warning, because the values are all the same width; there is no narrowing conversion, just overflow.
Therefore, using size_t is insufficient to guard against errors in array dimensions.
An alternative is to use a type you expect to be wide enough for your calculations, perhaps uint32_t. Given NumberOfGroups and such as uint32_t types, then:
const uint32_t N = NumberOfGroups * ElementsPerGroup + Header;
will produce a correct value for N. Then you can test it at run-time to guard against errors:
if ((size_t) N != N)
Report error…
uint8_t values[(size_t) N];
I have a 2D array A and a pointer ptr pointing somewhere inside it. I know how to compute the row number but the actual type of the expression seems non-portable:
#include <stdio.h>
int main(void) {
int A[100][100];
int *ptr = &A[42][24];
printf("row number is %d\n", (ptr - A[0]) / (sizeof(A[0]) / sizeof(A[0][0])));
printf("col number is %d\n", (ptr - A[0]) % (sizeof(A[0]) / sizeof(A[0][0])));
return 0;
}
On OS/X, the clang compiler complains this way:
warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
On Linux, gcc gives a similar warning, but on Windows, I get a different diagnostic:
warning: format specifies type 'int' but the argument has type 'unsigned long long' [-Wformat]
What is the actual type of this expression?
Is there a way to pass the expression to printf without an ugly cast?
The difference of 2 pointers has type ptrdiff_t, a signed integer type defined in <stddef.h>. The printf length modifier for this type is t. The difference of 2 pointers can be printed directly with:
printf("pointer difference: %td\n", ptr - A[42]);
The size of the subarray dimension (sizeof(A[0]) / sizeof(A[0][0])) is size_t, the unsigned type f the result of the sizeof operator defined in <stddef.h>.
The printf length modifier for this type is z. The size of an object can be printed directly with:
printf("array size in bytes: %zu\n", sizeof(A));
ptrdiff_t is required by the C standard to be able to represent values between -65535 and 65535 at least, while size_t must have a range of at least 0 to 65535.
The question is: what is the type of the division of a ptrdiff_t by a size_t?
The type is determined by applying the arithmetic conversions as specified in 6.3.1.8 Usual arithmetic conversions:
Otherwise (if both operands have integer types), the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:
If both operands have the same type, then no further conversion is needed.
Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.
Depending on the actual types used for ptrdiff_t and size_t, the type of the result can be different:
Integer promotion works this way: if type int can represent all values of its type, it is converted to int, if unsigned does, it is converted to unsigned, otherwise the type is unchanged.
Hence if size_t is smaller than int, size_t gets promoted to int, a signed type, and the division is performed as a signed division, both operands are first converted to the larger type of int and ptrdiff_t (very likely to be int as well in this case).
If size_t is type unsigned int and ptrdiff_t is type int, the ptrdiff_t is converted to unsigned int and the division is performed as an unsigned division with a result type unsigned int.
Conversely, if size_t is unsigned int and ptrdiff_t is type long int, the size_t operand is converted to type long int, the division is then a signed division and the resulting type is long int.
If size_t is unsigned long int and ptrdiff_t is type long int (Linux and OS/X 64-bit), the ptrdiff_t is converted to unsigned long int and the division is an unsigned division with resulting type unsigned long int.
If size_t is unsigned long long int and ptrdiff_t is type long long int (Windows 64-bit), the ptrdiff_t is converted to unsigned long long int and the division is an unsigned division with resulting type unsigned long long int.
More exotic architectures might have other combinations for types size_t and ptrdiff_t, resulting in more possibilities for the resulting type, such as long long int.
As a consequence, the type of the row computation is implementation defined: it can be signed or unsigned and different from both size_t and ptrdiff_t.
There are multiple ways to produce a consistent type and format for the printf statement:
Using a cast:
printf("row number is %d\n", (int)((ptr - A[0]) / (sizeof(A[0]) / sizeof(A[0][0]))));
Using an intermediary variable:
int row = (ptr - A[0]) / (sizeof(A[0]) / sizeof(A[0][0])));
printf("row number is %d\n", row);
Using an extra operation to force a larger type (not perfect as size_t could be larger than unsigned long long):
printf("row number is %llu\n", 0ULL + (ptr - A[0]) / (sizeof(A[0]) / sizeof(A[0][0])));
Note that the printf formats %zu for size_t and %td for ptrdiff_t cannot be used since the type of the expression is not necessarily size_t not ptrdiff_t. To make matters worse for Windows users, these standard length specifiers are not supported by the Microsoft C runtime library. As suggested by Jean-François Fabre, there is a work-around for MingW users who compile C code with gcc and generate native Windows applications: specifying -D__USE_MINGW_ANSI_STDIO on the command line tells gcc to use its own version of printf instead of that of the Microsoft runtime.
Final note: the expression ptr - A[0] actually invokes undefined behavior if ptr does not point inside the first row of the array, as specified in 6.5.6 Additive operators:
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements.
It's hard to say and there is, I think, no hard and fast rule that defines a type that's consistent for all platforms. There's no standard library typedef for such an expression.
If you're using C++, consider using auto to declare such a type, and std::cout to print a value of such a type: rely on the compiler to choose the appropriate overload for <<.
If I have this code:
int A;
unsigned int B;
if (A==B) foo();
the compiler will complain about mixed types in comparison. If I cast A like this:
if ((unsigned int) A==B) foo();
does this instruct the compiler to insert code to convert A from int to unsigned int? Or does it just tell the compiler don't worry about, ignore the type mismatch?
UPDATE: If this is unsafe (as pointed out below), how should I handle this comparison? (Wouldn't assigning the contents of an int to an unsigned int for later comparison also be unsafe)
UPDATE: Wow are there some different answers (from people with thousands of posts). I've accepted what seems like the best, but anyone reading this question should read ALL answers carefully.
When casting, at least at the conceptual level, compiler will create a temporary variable of the type specified in the cast expression.
You may test that this expression:
(unsigned int) A = B; // This time assignment is intended
will generate an error pointing modification of a temporary (const) variable.
Of course compiler is free to optimize away any temporary variables created through a cast. Nevertheless a valid method to build a temporary must exist.
The cast implies a conversion, if necessary. But this is problematic for negative values. They are mapped to positive values on the unsigned type. Thus you have to make sure a negative value never compares equal any (positive) unsigned value:
int A;
unsigned int B;
...
if ( (A >= 0) && (static_cast<unsigned int>(A) == B) )
foo();
This works because the unsigned variant of an integer type is guaranteed to hold all positive values (including 0) of the corressponding signed type.
Notice the usage of a static_cast instead of the "classic" C-style cast.
With plain types, in C and C++, == is always done with both operands converted to the same type. In OP's code, A is converted to unsigned first.
If I cast ... does this instruct the compiler to insert code to convert A from int to unsigned int?
Yes, but that code would have occurred anyway. Without the cast, the compiler is simple warning that it is going to do something that the programmer may not have intended.
Or (If I cast ) does it just tell the compiler don't worry about, ignore the type mismatch?
The type mis-match is not ignored. By supplying the cast, there is no type mis-match to warn about.
How should I handle this comparison?
Insure A is not negative, then convert to unsigned with a cast.
int A;
unsigned int B;
// if (A==B) foo();
if (A >= 0 && (unsigned)A == B) foo();
Every non-negative int can be converted to an unsigned with no value change.
The range of nonnegative values of a signed integer type is a subrange of the
corresponding unsigned integer type C11dr §6.2.5 9
So you question is just about a signed/unsigned comparison.
C++ standard says in clause 5 Expressions [expr] § 10:
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
This pattern is called the usual arithmetic conversions, which are defined as follow:...
Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the
rank of the type of the other operand, the operand with signed integer type shall be converted to
the type of the operand with unsigned integer type.
and in 4.7 Integral conversions [conv.integral] §2
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source
integer (modulo 2n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s
complement representation, this conversion is conceptual and there is no change in the bit pattern (if there
is no truncation). —end note ]
That means that on a common system using 2-complement for negative numbers and 32 bits for an int or unsigned int, (unsigned int) -1 will end in 4294967295.
It may be what you want or not, the compiler just warn you that it will consider them as equal.
If it is not what you want, just first test whether the signed value is negative. If it is, say that they are not equal an skip the equality comparison.
It depends on type of cast and what you are casting. In your particular case nothing is going to happen, but in other cases the actual code will be performed. Simplest example:
void foo(double d) {};
...
int x;
foo(static_cast<double>(x));
In this example there would be code generated.
When I am doing arithmetic operations with size_t type (or unsigned long), how careful should I be with decorating integer constants with type literals. For example,
size_t a = 1111111;
if (a/2 > 0) ...;
What happens when compiler does the division? Does it treat 2 as integer or as unsigned integer? If the former, then what is the resulting type for (unsigned int)/(int)?
Should I always carefully write 'u' literals
if (a/2u > 0) ...;
for (a=amax; a >= 0u; a -= 3u) ...;
or compiler will correctly guess that I want to use operations with unsigned integers?
2 is indeed treated as an int, which is then implicitly converted to size_t. In a mixed operation size_t / int, the unsigned type "wins" and signed type gets converted to unsigned one, assuming the unsigned type is at least as wide as the signed one. The result is unsigned, i.e. size_t in your case. (See Usual arithmetic conversions for details).
It is a better idea to just write it as a / 2. No suffixes, no type casts. Keep the code as type-independent as possible. Type names (and suffixes) belong in declarations, not in statements.
The C standard guarantees that size_t is an unsigned integer.
The literal 2 is always of type int.
The "usual artihmetic converstions guarantee that whenever an unsigned and a signed integer of the same size ("rank") are used as operands in a binary operation, the signed operand gets converted to unsigned type.
So the compiler actually interprets the expression like this:
a/(size_t)2 > (size_t)0
(The result of the > operator or any relational operator is always of type int though, as a special case for that group of operators.)
Should I always carefully write 'u' literals
Some coding standards, most notably MISRA-C, would have you do this, to make sure that no implicit type promotions exist in the code. Implicit promotions or conversions are very dangerous and they are a flaw in the C language.
For your specific case, there is no real danger with implicit promotions. But there are cases when small integer types are used and you might end up with unintentional change of signedness because of implicit type promotions.
There is never any harm with being explicit, although writing an u suffix to every literal in your code may arguably reduce readability.
Now what you really must do as a C programmer to deal with type promotion dangers, is to learn how the integer promotions and usual arithmetic conversions work (here's some example on the topic). Sadly, there are lots of C programmers who don't, veterans included. The result is subtle, but sometimes critical bugs. Particularly when using the bit-wise operators such as shifts, where change of signedness could invoke undefined behavior.
These rules can be somewhat tricky to learn as they aren't really behaving rationally or consistently. But until you know these rules in detail you have to be explicit with types.
EDIT: To be picky, the size of size_t is actually not specified, all the standard says is that it must be large enough to at least hold the value 65535 (2 bytes). So in theory, size_t could be equal to unsigned short, in which case promotions would turn out quite different. But in practice I doubt that scenario is of any interest, since I don't believe there exists any implementation where size_t is smaller than unsigned int.
Both C++ and C promote signed types to unsigned types when evaluating an operator like division which takes two arguments, and one of the arguments is an unsigned type.
So the literal 2 will be converted to an unsigned type.
Personally, I believe it's better to leave promotion to the compiler rather than be explicit: if your code was ever refactored and a became a signed type then a / 2u would cause a to be promoted to an unsigned type, with potentially disastrous consequences.
size_t sz = 11;
sz / 2 = 5
sz / (-2) = 0
WHY?
sz is treated as unsigned int because size can not be negative. When doing an arithmetic operation with an unsigned int and an int, the int is turned into unsigned int.
From "CS dummies"