I have recently downloaded the MinGw compiler and for some reason it does not display and warning messages when I should be doing a explicit casts.
For example:
double x=9.97;
int y=x;
This seems to be ok with the compiler. I was just wondering do I need to install some other package
There is no cast required when assigning a double to an int. The decimal part is simply truncated. If you want warnings on this you can use -Wconversion or -Wfloat-conversion.
To complement the other answer, a technical explanation about implicit conversion semantics can be found on http://en.cppreference.com/w/c/language/conversion:
A finite value of any real floating type can be implicitly converted to any integer type. Except where covered by boolean conversion above, the rules are:
- The fractional part is discarded (truncated towards zero).
. If the resulting value can be represented by the target type, that value is used
. otherwise, the behavior is undefined
Related
In C11 (and later) integer constant expression shall only have operands that are, in particular:
floating constants that are the immediate operands of casts
The following code:
int a[ A > B ? 16 : 32 ];
when A and B are floating constants is invalid in C:
$ echo '#include "t576.h"' | clang -std=c11 -pedantic -Wall -Wextra -DA=1.0 -DB=2.0 -c -xc -
In file included from <stdin>:1:
./t576.h:1:5: warning: size of static array must be an integer constant expression [-Wpedantic]
but valid in C++:
$ echo '#include "t576.h"' | clang++ -std=c++11 -pedantic -Wall -Wextra -DA=1.0 -DB=2.0 -c -xc++ -
<nothing>
What is the origin / rationale of this requirement?
Extra question: In the future C standard revisions will it be useful to remove this requirement?
What is the origin / rationale of this requirement?
It means C compilers are not required to be able to execute floating-point arithmetic within the compiler. When compiling for a target platform different from the compiler host platform, replicating the exact behavior of the target floating-point operations can require a lot of work. (This was especially so prior to widespread adoption of the IEEE 754 standard for floating-point arithmetic.)
To implement floating-point semantics in a C program, the compiler only has to be able to convert the constants in source code to the target floating-point format and take the integer portion of them (in a cast). It does not have to be able to perform general arithmetic operations on them. Without this requirement, the compiler would have to reproduce the floating-point arithmetic operations of the target platform. So, if a program uses floating-point arithmetic, the compiler can implement that just by generating instructions to do the arithmetic; it does not have to do the arithmetic itself. This is also true for arithmetic constant expressions, which can be used as initializers: The compiler is not strictly required by the C standard to compute the value of the initializer. It can generate instructions that compute the value when the program starts running (for initialization of static objects) or when needed (for initialization of automatic objects).
In contrast, integer constant expressions can be used in places where the compiler needs the value, such as the width of a bit-field. So the compiler must be able to compute the value itself. If it were required to be able to do floating-point arithmetic to get the value, this would add considerable burden to writing some compilers.
Extra question: In the future C standard revisions will it be useful to remove this requirement?
Removing it will provide some opportunity for C program writers to use additional constant expressions and will require C compiler writers to do more work. The value of these things is subjective.
The rationale is common sense: they don't want to allow users to declare an array of some 3.1415 items - the array size needs to be an integer, obviously.
For many operators in C, the usual arithmetic conversions would turn the end result into floating point whenever a floating point operand is present. In case of ?: specifically that doesn't happen, since the result is the 2nd or 3rd operand. Also the > operator does always return int so it doesn't really apply there either.
If you don't immediately cast floating point operands to an integer type, as told in the definition of an integer constant expression that you quote, then it will become an arithmetic constant expression instead, which is a broader term.
So you can do this:
int a[ (int)1.0 > (int)2.0 ? 16 : 32 ]; // compliant
But you can't do this:
int a[ 1.0 > 2.0 ? 16 : 32 ]; // not compliant
Consider int a[ (int)1.0 > (int)2.0 ? 16.0 : 32 ]; (not compliant either). Here the condition always evaluates as false. We should get size 32, but because of the special implicit conversion rules of ?: the 2nd and 3rd operands are balanced per the usual arithmetic conversions, so we end up with 32.0 of type double. And if that in turn would lead to a floating point number that cannot be exactly represented, we would get a floating point array size.
We recently took an exam were we got this question:
Consider this fragment of code:
FILE * pFile;
pFile = open ("myfile.txt","w+");
fprintf (pFile, "%f %s", 3.1416, "PI");
Which of the following statements are true?
A)The program generates error at compile time
B)The program generates error at runtime
C) . . .
D) . . .
We couldn't use the compiler, and the information wrote is the only thing we had.
The correct answer ended up being B, error at runtime, can someone explain me thoroughly why that is?
I know the compiler generates a warning, but the point here is to understand why the compiler let us compile this code in the first place instead of giving us an error.
My guess is that open, even though doesn't give a pointer back(which is an address), gives the fp which is still an int, so in the eyes of the compiler isn't wrong syntax, but at runtime it probably tries to access a private memory address which leads to an error.
p.s.
I know that the correct function should have been fopen, but that still doesn't explain why
This code has two specific issues:
The second parameter to open expects an int but a char * is passed instead
open returns an int but that value is assigned to a FILE *.
The compiler flags these as warnings instead of errors because the language allows a pointer to be converted to an integer, and for an integer to be converted to a pointer. However, doing so is generally implementation defined and usually (as in this case) but not always indicates a problem.
Section 6.3.2.3 of the C standard describes these conversions:
5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined,
might not be correctly aligned, might not point to an entity
of the referenced type, and might be a trap representation.
6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type,the behavior
is undefined. The result need not be in the range of values
of any integer type.
In the following code from core_cm4.h why is there a double cast ((uint32_t)(int32_t)IRQn)?
For example in the following function:
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
What is the purpose of this?
Since CM4 software implements negative interrupt sources for core, you have to cast value first to 32bit signed integer and later to unsigned 32bit to make proper right shift with padding zeros on the left side of number.
CM4 uses -15 to -1 as CM4-Core sources and from 0 to next as vendor specific sources.
By looking at that snippet, it is clear that whoever wrote it was confused over how implicit type promotion rules work. In addition, the >> 5UL looks very fishy and when I see that I immediately suspect that this code base suffers from a poor understanding of MISRA-C; possibly they are using a bad static analyser which spits out false positives.
A visit at Github proves my suspicion to be correct, there's comments stating that the intention is to follow MISRA-C:2004.
MISRA-C demands that no dangerous, implicit type promotions may occur. The casts are some failed attempts to silence a static analyser, without an understanding why the tool gave those warnings.
Correct, MISRA-C (2004 and 2012) compliant code would be this:
NVIC->ISER[((uint32_t)IRQn>>5UL)] = (1UL << ((uint32_t)IRQn & 0x1FUL));
(MISRA-C has a requirement that complex sub-expressions must use parenthesis despite what operator precedence there is.)
This code is still messy, so it should preferably be rewritten for readability, into something that will produce exactly the same machine code:
uint32_t ISER_index = ((uint32_t)IRQn >> 5UL);
uint32_t shift_n = ((uint32_t)IRQn & 0x1FUL);
NVIC->ISER[ISER_index] = (1UL << shift_n);
Side note:
MISRA-C:2004 demanded that the result of the shift expression should be immediately cast to the "underlying type" (MISRA term). Thus one could also have written (IRQn_Type)(IRQn >> 5UL) and it would still be MISRA-C:2004 compliant.
However, there is nothing in MISRA preventing you to adding your own cast to a different type, such as uint32_t, before the shift. This is a better thing to do, since it eliminates the implicit promotion entirely.
For those who are confused about how the implicit type promotions work in C, see Implicit type promotion rules.
Assuming IRQn is an integer (any signed integer type) in the range you say, then (uint32_t)(int32_t)IRQn is exactly the same as (uint32_t)IRQn.
The author of the code possibly didn't understand C type conversion rules; which are based on values, not representations. Converting -3, for example, to uint32_t always gives UINT32_MAX - 2 regardless of which data type the -3 was. It's the value of "negative 3" that matters.
(The other answer explains the difference between using a cast and no cast at all).
There's a rationale for the warning here, but that fails to answer the whole picture. For example the following code triggers the warning:
(int)round(M_PI);
but on the other hand the following code doesn't:
double d;
(int)(d = round(M_PI));
this doesn't either:
(int)M_PI;
the rationale was that you shouldn't convert to int by simply casting, but you should use round, floor or similar function. However using round will still trigger the warning, but as seen above typecasting a constant or assigned variable doesn't.
So if it's that bad to cast from double to int, then why doesn't the warning trigger when you write (int)d or (int)M_PI? In what way is one supposed to circumvent the warning in case you want to convert the return value? Is there a warning that would handle these perilous conversions in a more correct/reasonable way?
-Wbad-function-cast (C and Objective-C only)
Warn when a function call is cast to a non-matching type. For example, warn if a call to a function returning an integer type is cast to a pointer type.
As its name suggests, -Wbad-function-cast only warns when you are casting function calls to a non-matching type. It doesn't warn on all casts. This explains why you are not getting that warning for your last two examples:
(int)(d = round(M_PI)); doesn't trigger a warning because it is casting double d to int after it has been assigned a value.
(int)M_PI; doesn't trigger a warning because M_PI is usually implemented as #define M_PI 3.14159...; it is simply a numeric token and not a function call.
You are right that it could be bad to cast from double to int as you are potentially losing information. You could avoid the GCC warning by simply assigning the function return value to a matching type, then casting later, as in your two examples that don't trigger the warning.
Of course, the point of the warning is not to force you to write extra code to do the same thing. Even for functions that "return an integral value" like round(), the return value may be too big to fit in an int. What you should be doing is checking to see if the value is safe to cast first.
If you like the warning generally but are annoyed that there's no way to write an explicit cast that suppresses it, on GCC you can do this:
_Pragma ("GCC diagnostic push");
_Pragma ("GCC diagnostic ignored \"-Wbad-function-cast\"");
OCR1A = ((uint16_t) (function_returning_double));
_Pragma ("GCC diagnostic pop");
I would only resort to this in contexts where you don't want to introduce an intermediate value (i.e. in a macro). As others have noted (in here: What is the purpose of gcc's -Wbad-function-cast?), a gratuitous lrint()/lround() might not get optimized away. And inserting an intermediate value in a macro is unhygienic.
My CCS 6.1 ARM compiler (for LM3Sxxxx Stellaris) throws a warning:
"MISRA Rule 10.1. The value of an expression of integer type shall not be implicitly converted to a different underlying type if the expression is
not constant and is a function argument"
for following code:
static uint32_t diagBaseAddress;
void diagCbGetBaseAddress(uint32_t * addr);
...
diagCbGetBaseAddress(&diagBaseAddress); // line where warning is issued
...
I don't see a problem in my code. Is it false positive or my bug?
Yes, it is a false positive. Rule 10.1 of MISRA-C:2004 is concerned about implicit type promotions of integer types. Pointers have nothing to do with that rule.
Though make sure that none of the adjacent code lines contain the actual problem, the tool could simply be pointing at the wrong line.
(I can tell it is the 2004 version because it mentions underlying type. In the 2012 version, the concept of underlying type was replaced.)