This code works fine:
double a =2.12345;
int b{a}; // According to primer error: narrowing conversion required
int c(a); //This is fine
Is it something which I am missing? For me when a float/double is assigned to int the values on left of the decimal are printed (floor value). Primer says error.
Is it something which I am missing?
The unfortunate detail of compilers deviating from the standard. GCC doesn't enforce it unless you tell it that it should. Try compiling with the -pedantic-errors option.
The primer isn't wrong, it's an ill-formed program according to the C++ standard alone. But compilers may choose to accept it as an extension, such is what GCC does.
Some compilers (rightfully) enforce it by default. MacOSX clang for example would return an error:
type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
For GCC, the option -Wconversion should generate a warning.
Related
Considering the following piece of code:
#include <iostream>
auto main() -> int {
double x(7.0);
int i{x};
std::cout << "i = " << x << std::endl;
return 0;
}
When compiled in GCC4.9 it compiles fine with only a warning:
warning: narrowing conversion of ‘x’ from ‘double’ to ‘int’ inside { }
Compiling with either Clang3.3 or VC++2013 gives a compile error:
error: type 'double' cannot be narrowed to 'int' in initializer list
error C2397: conversion from 'double' to 'int' requires a narrowing
Questions:
Which of the compilers is right according to the standard?
Is there any reason why the compilers mentioned above should exhibit such diverse behaviour?
The answer
Both compilers are correct!
Explanation
The Standard doesn't distinguish between an error and a warning, both go under the category of Diagnostics.
1.3.6 diagnostic message [defns.diagnostic]
message belonging to an implementation-defined subset of the implementation's output messages
Since the Standard says that a diagnostic is required in case a program is ill-formed, such as when a narrowing-conversion takes place inside a braced-initializer, both compilers are confirming.
Even if the program is ill-formed from the Standards point of view, it doesn't mandate that a compiler halts compilation because of that; an implementation is free to do whatever it wants, as long as it issues a diagnostic.
The reason for gcc's behavior?
Helpful information was provided by #Jonathan Wakely through comments on this post, below are a merge of the two comments;
he exact reason is that GCC made it an error at one point and it broke ALL THE PROGRAMS so it got turned into a warning instead. Several people who turned on the -std=c++0x option for large C++03 codebases found harmless narrowing conversions to cause most of the porting work to go to C++11See e.g. PR 50810 where Alisdair reports narrowing errors were >95% of the problems in Bloomberg's code base.In that same PR you can see that unfortunately it wasn't a case of "let's just issue a warning and be done with it" because it took a lot of fiddling to get the right behaviour.
I was just wondering why this works in Clang 4.0:
unsigned cnt = 42;
int k[cnt];
But this won't:
unsigned cnt = 42;
string bad[cnt];
I just checked C++ primer 5th edition. It says that:
the dimension must be known at compile time, which means that the
dimension must be a constant expression
If that's true, why does the int k[cnt]; work?
Neither snippet works in C++.
However, in C, it's possible to use non-constant expressions as array sizes. Some compilers (for example, GCC without -pedantic option) support that C feature in C++ code.
As for the difference between element types, it's compiler-specific. GCC compiles both. clang++ prohibits non-POD types (such as std::string) in this case.
What compiler are you using, I am using gcc and both const and nonconst works fine.
It is not a matter of c, arrays are not meant to be defined through variables, only macros and const expressions.
It's a matter of compiler's interpretation, I doubt it is related to standards.
Is clang 4.0 actually apple xcode clang? i think that is actually version 3.1. clang offers a nice explanation itself:
warning: variable length arrays are a C99 feature
[-Wvla-extension]
int k[cnt];
Can anyone please explain to me, why the compiler allows initialize variables of built-in type if the initializer might lead to the loss of information?
For example C++ Primer, the 5th edition says, that The compiler will not let us list initialize variables of built-in type if the initializer might lead to the loss of information.
but my compiler gcc v 4.7.1 initialized variable a in the following code successfully:
long double ld = 3.1415926536;
int a{ld};
there was just warning: narrowing conversion of ‘ld’ from ‘long double’ to ‘int’ inside { } [-Wnarrowing].
One of the features of initializer lists is that narrowing conversions are not allowed. But the language definition doesn't distinguish between warnings and errors; when code is ill-formed it requires "a diagnostic", which is defined as any message from a set of implementation-defined messages. Warnings satisfy this requirements. That's the mechanism for non-standard extensions: having issued a warning, the compiler is free to do anything it wants to, including compiling something according to implementation-specific rules.
You can set the compiler flag to flag all warnings as error. In that case only it will stop you from doing like that. Otherwise it will only be a warning.
This issue has been coming up lately. With gcc-4.7 a command line switch turns on the required behaviour:
g++ -Werror=narrowing ...
I have the following code:
typedef void VOID;
int f(void);
int g(VOID);
which compiles just fine in C (using gcc 4.3.2 on Fedora 10). The same code compiled as C++ gives me the following error:
void.c:3: error: ‘<anonymous>’ has incomplete type
void.c:3: error: invalid use of ‘VOID’
Now, this is something in external library and I would like the owner to fix that problem. So I have a question - does C++ standard forbids this construct? Could you give me a pointer/citation? The only thing I can recall is that function declaration with (void) to signal empty parameter list is deprecated in C++, but I don't understand why typedefed VOID does not work.
Yes, as far as i know the second declaration is invalid in C++ and C89, but it is valid in C99.
From The C99 draft, TC2 (6.7.5.3/10):
The special case of an unnamed parameter of type void as the only item in the list
specifies that the function has no parameters.
It's explicitly talking about the type "void", not the keyword.
From The C++ Standard, 8.3.5/2:
If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list.
That it means the actual keyword with "void", and not the general type "void" can also be seen from one of the cases where template argument deduction fails (14.8.2/2):
Attempting to create a function type in which a parameter has a type of void.
It's put clear by others, notable in one core language issue report here and some GCC bugreports linked to by other answers.
To recap, your GCC is right but earlier GCC versions were wrong. Thus that code might have been successfully compiled with it earlier. You should fix your code, so that it uses "void" for both functions, then it will compile also with other compilers (comeau also rejects the second declaration with that "VOID").
gcc bugs. Edit: since it wasn't clear enough, what I meant was gcc 4.3.2 was compiling it due to bugs. See #32364 and #9278.
I just put your code in a .cpp file, and it compiled with no problems in VS2005, SUSE, Redhat, and Solaris, so I guess your specific gcc version does not approve of this.
Gal
In C the following horror is valid:
myFunc()
{
return 42; // return type defaults to int.
}
But, what about in C++? I can't find a reference to it either way...
My compiler (Codegear C++Builder 2007) currently accepts it without warning, but I've had comments that this is an error in C++.
It's ill-formed in C++. Meaning that it doesn't compile with a standard conforming compiler. Paragraph 7.1.5/4 in Annex C of the Standard explains the change "Banning implicit int".
Implicit return types are valid in C89, but a lot of compilers warn about it.
They are not valid in C++, nor in C99.
So, it's definitely 'ill formed' C++, but it seems many compilers accept it with a warning at best.
Codegear C++Builder 2007: No error or warning at all
G++: Requires -W -Wall to generate warning , or -pedantic to generate error (Piotr)
MSVC 8: produces an error (tfinniga)
others...?
Please add to/correct this list!
This is not legal C++, but some compilers will accept it either silently or with a diagnostic.
As posted, it is ill-formed. MSVC 8 gives the following error:
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int