I am trying to capitalize the first character of a std::string, using the same method mentioned here. For example for the following program
#include <cctype>
#include <iostream>
#include <string>
int main()
{
std::string name = "foobar";
name[0] = std::toupper(name[0]);
std::cout << name;
}
I am expecting the output to be
Foobar
When I compile this online (using GCC 4.9.2) I get the correct output without any warnings. However, when I compile the same code in Visual Studio 2013, I get a warning during the assignment back from toupper
warning C4244: '=' : conversion from 'int' to 'char', possible loss of data
Is the above method valid according to the C++ standard or is the warning correct? Otherwise is this just a false warning by Visual Studio?
The warning is correct as far the types go; the type of std::toupper as defined in the standard is:
int toupper( int ch );
Mostly because it's a remnant from the dark C ages (the cctype header is a hint at that).
However, this is just a part of the story. There's another toupper residing in the locale header:
template< class charT >
charT toupper( charT ch, const locale& loc );
This one shouldn't give you any warnings. If you're not sure what locale to provide, std::locale() will give you the default one.
std::toupper comes from the C standard, not C++, and has an annoying interface in that it takes and returns an int not a char. Using static_cast<char>(std::toupper(name[0])) will suit you.
The warning is correct, compiler will implicitly cast from int to char but this might cause lost of data in some cases. To see warning under gcc you need to add -Wconversion compiler option. Which will generate:
main.cpp: In function 'int main()':
main.cpp:8:13: warning: conversion to '__gnu_cxx::__alloc_traits<std::allocator<char> >::value_type {aka char}' from 'int' may alter its value [-Wconversion]
name[0] = std::toupper(name[0]);
^
Foobar
Why it is not present when -Wall is set, read here:
https://gcc.gnu.org/wiki/NewWconversion
Why isn't Wconversion enabled by -Wall or at least by -Wextra?
Implicit conversions are very common in C. This tied with the fact
that there is no data-flow in front-ends (see next question) results
in hard to avoid warnings for perfectly working and valid code.
Wconversion is designed for a niche of uses (security audits, porting
32 bit code to 64 bit, etc.) where the programmer is willing to accept
and workaround invalid warnings. Therefore, it shouldn't be enabled if
it is not explicitly requested.
Related
So I want to use char8_t data type in my code. But my compiler shows me that it could not find an identifier like char8_t , which probably means it could not find required header file or definitions for it.
So can anyone tell me what header files / definitions should I use to get the char8_t data type? The language is C++. I'll be thankful if you can also answer for C.
PS:<cwchar> did not work.
Edit:
My code:
#include <iostream>
#include <cwchar>
using namespace std;
int main()
{
char c='a';
wchar_t w=L'A';
char8_t c8=u8'c';
char16_t c16=u'D';
char32_t c32=U'K';
cout<<"Data Type"<<"\t"<<"Size"<<"\n"
<<"char"<<"\t \t"<<sizeof(c)<<" bytes"<<"\n"
<<"wchar_t"<<"\t \t"<<sizeof(w)<<" bytes"<<"\n"
<<"char8_t"<<"\t"<<sizeof(c8)<<"\n"
<<"char16_t"<<"\t"<<sizeof(c16)<<" bytes"<<"\n"
<<"char32_t"<<"\t"<<sizeof(c32)<<" bytes"<<"\n";
return 0;
}
My compiler throws this error:
WideCharacters.cpp: In function 'int main()':
WideCharacters.cpp:8:5: error: 'char8_t' was not declared in this
scope; did you mean 'wchar_t'?
8 | char8_t c8=u8'c';
| ^~~~~~~
| wchar_t
WideCharacters.cpp:15:31: error: 'c8' was not declared in this
scope; did you mean 'c'?
15 | <<"char8_t"<<"\t"<<sizeof(c8)<<"\n"
| ^~
| c
Edit-2:
I have my C++ standard set to C++20 in VS code so there is no problem with standard.
char8_t is a keyword. It's built into the language, so you don't need any headers.
If it doesn't work, either your compiler doesn't support it, or you forgot to enable C++20 support (e.g. -std=c++20 in GCC).
The problem here is possibly the compiler is not able to identify that this is a C++20 feature.
Compile using this:
g++ -Wall -std=c++20 "yourFileName".cpp
replace youFileName with that of the file name.
i'm looking for a compiler switch (or _SOME_MACRO) that will warn about or disallow features or constructs that are no longer recommended (although still allowed) for the "selected" c++year.
eg. when compiling g++ with switch -std=c++17 i would like a warning when using the obsolete superseded "typedef" construct.
that is, i would like to code in an "orthodox c++17" subset of c++17 ;-)
typedef int Sequence; // I would like a warning here
edit: to state my desire more clearly: i would like to program in the ideal/reformed subset of c++17 that the authors would have created, had they chosen to disregard any and all backwards compatibility. i know that this is not a strictly formal and true statement of affairs, but i trust that it may suffice to make my point.
Well, with gcc and some macro abuse you could do this:
#define typedef _Pragma("GCC warning \"typedef is deprecated in my code base\"") typedef
typedef int Sequence; // I would like a warning here
will generate in gcc:
<source>:3:13: warning: typedef is deprecated in my code base
3 | typedef int Sequence; // I would like a warning here
| ^~~~~~~~~~~~~~~~~~~~~~~
You can change that _Pragma("GCC warning \"string\"") into _Pragma("message \"string\") or really to _Pragma("GCC error \"string\"") to get a compilation error. You could add it as a parameter to your compilation line -D'typedef=_Pragma("GCC warning \"I consider typedef to be deprecated\"")'.
The C++ has [[deprecated]], but it deprecates the variable, not the typedef, so it wouldn't have the proper intention. It would work on more compilers, so if your team/you agree on a convention, you could use it, as a hint that you agree not to use typedef in your code.
#define typedef [[deprecated]] typedef
typedef int Sequence; // I would like a warning here
int main() {
Sequence a;
}
will output in gcc 9.1:
<source>: In function 'int main()':
<source>:6:14: warning: 'Sequence' is deprecated [-Wdeprecated-declarations]
6 | Sequence a;
| ^
<source>:3:13: note: declared here
3 | typedef int Sequence; // I would like a warning here
| ^~~~~~~~
As you may have guessed, since typedef is a compiler directive rather than a function or class, there is no way to redefine it the way you would a function or macro using #undef and then redefining.
#include <cstdio>
#undef printf
[[deprecated( “please don’t use printf!” )]]
int printf(const char *format, ...) {
Your best bet is to tie a linter like clang-tidy into your build system to preprocess the syntax. After all, you are wanting to give a warning directive to the programmer not to the compiler. It would be sensible to leave the compiler to compilation and not give it additional work.
Also, bear in mind typedef is perfectly valid C++ and has usefulness outside of type-aliasing the same way union is valid and has its role to play even with std::variant available.
Compiler developers do add these warnings themselves when a construct is completely obsoleted by the standards committee. register would be a prime example.
I have the following code
#include <iostream>
using namespace std;
int dmult(int a, int b){
return 2*a*b;
}
int main(void)
{
double a = 3.3;
double b = 2;
int c = dmult(a,b);
cout << c << endl;
return 0;
}
It compiles with MinGW without problems. The result is (as I thought) false. Is it a problem of the compiler that there is no warning, that a function expecting integers, but fed with doubles, can compile without warning even if the input type is wrong? Does it mean that C++ ignores the input type of a function? Shouldn't it realize that the function arguments have the wrong type?
double's are implicitly convertible to ints (and truncated), and the compiler is not forced by the standard to emit a warning (it tries its best to perform the conversion whenever possible). Compile with -Wconversion
g++ -Wconversion program.cpp
and you'll get your warning:
warning: conversion to 'int' from 'double' may alter its value [-Wfloat-conversion]
The typical warning flags -Wall -Wextra don't catch it since many times it is the programmer's intention to truncate double's to int's.
Live example here.
c++ automatically casts floats and doubles to integer literals by truncating them. so 3.3 becomes 3 when you call dmult(3.3,2)
When the following bit of code is compiled with the diab c++ compiler (dplusplus), it generates a conversion warning on the third line. It can be resolved by casting the result of the (&&) operator to anything other than bool.
Code:
bool first = 1;
bool second = 1;
bool ret = (first && second); //generates compile warning
Error:
warning: (etoa:1643): narrowing or signed-to-unsigned type conversion
found: int to unsigned char
I verified that nothing is defining bool to another type. Does this look like a compiler issue, or is there something else I might be missing that could cause this?
Wind River's web site indicates that the Diab compiler can compile either C or C++.
In C, the && operator yields a result of type int, with the value 0 or 1. That's consistent with the warning you're seeing.
As of the 1990 ISO standard, C did not have a built-in bool type. It was common to define bool as a typedef. It appears from the message that bool is a typedef for unsigned char, probably in some header. The 1999 ISO C standard adds a new predefined boolean type called _Bool; the identifier bool is defined in <stdbool.h> as a macro that expands to _Bool. But if <stdbool.h> isn't included, bool can be defined in some other way.
In C++, && yields a result of type bool with the value false or true, and bool is a distinct fundamental type. This has been the case at least since the 1998 ISO C++ standard.
I strongly suspect you're getting this warning because you're compiling your code as C rather than as C++. A less likely possibility is that the Diab compiler doesn't fully conform to the C++ standard; it might have a way to tell it to conform more closely.
I haven't used the Diab compiler. Typically you can control the language being compiled by using a particular file extension (typically .c for C and .cpp for C++), or by using a different command, or both.
Consult the compiler's documentation to find out how to invoke it as a conforming C++ compiler.
As an experiment, before changing the way you invoke the compiler, you might try adding a declaration:
int class;
to your source file. This is legal in C, but a syntax error in C++ (since class is a C++ keyword).
UPDATE:
The OP says he's definitely compiling as C++, not as C. But the warning message implies that && yields int, and that bool is the same type as unsigned char.
A warning doesn't directly indicate that the compiler is not conforming; compilers can warn about anything they like. But the content of this warning does suggest a compiler bug, or at least a compiler that doesn't conform to any C+
Any conforming C++ compiler must produce diagnostics for this program. What does your compiler do? (Please don't add any #include directives.)
int main() {
class dummy { }; // Just to make sure it's C++
bool b;
unsigned char c;
bool* pb = &c; // Invalid conversion
unsigned char* pc = &b; // Invalid conversion
}
And what output do you get when you compile and execute this program?
#include <iostream>
int main() {
std::cout << "__cplusplus = " << __cplusplus << "\n";
}
Edited to remove the first warning
The following code works as expected in g++ 4.4.0 under mingw32:
#include <cstdio>
int main()
{
long long x = 0xdeadbeefc0defaceLL ;
printf ("%llx\n", x) ;
}
But if I enable all warnings with -Wall, it says:
f.cpp: In function 'int main()':
f.cpp:5: warning: unknown conversion type character 'l' in format
f.cpp:5: warning: too many arguments for format
It's the same with %lld. Is this fixed in newer versions?
Edited again to add:
The warning doesn't go away if I specify -std=c++0x, even though (i) long long is a standard type, and (ii) %lld and %llx seem to be officially supported. For instance, from 21.5 Numeric conversions para 7:
Each function returns a string object holding the character representation of the value of
its argument that would be generated by calling sprintf(buf, fmt, val) with a format specifier of
"%d", "%u", "%ld", "%lu", "%lld", "%llu", "%f", "%f", or "%Lf", respectively, where buf designates
an internal character buffer of sufficient size.
So this is a bug, surely?
long long x = 0xdeadbeefc0defaceLL; // note LL in the end
And there is no ll length specifier for printf. The best you can get is:
printf ("%lx\n", x); // l is for long int
I've tested your sample on my g++, it compiles without errors even without -std=c++0x flag:
~$ g++ -Wall test.cpp
~$ g++ --version
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
So, yes, this fixed in newer versions.
For first warning I can say that you must use 0xdeadbeefc0defaceLL instead of 0xdeadbeefc0deface. After that other warnings may pass also.
I get the same warning compiling C using windows/mingw32.
warning: unknown conversion type character 'l' in format
So yes, probably a compiler/platform specific bug.
It's a Mingw-specific issue, because it calls the native Windows runtime for certain things, including this. See this answer.
%I64d works for me. In the answer linked above there is a more portable albeit less readable solution as well.