The following C++ code does not compile with VS2015:
#include <time.h>
#include <ctime>
void main()
{
const time_t t = std::time(nullptr);
std::tm tm = {};
std::localtime_s(&tm, &time);
}
The error messages are:
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
t.cpp
t.cpp(10): error C2039: 'localtime_s': is not a member of 'std'
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\ctime(17): note: see declaration of 'std'
t.cpp(10): error C2664: 'errno_t localtime_s(tm *const ,const time_t *const )': cannot convert argument 2 from 'time_t (__cdecl *)(time_t *const )' to 'const time_t *const '
t.cpp(10): note: There is no context in which this conversion is possible
What can be a workaround? (using std::localtime() is not an option).
Per [headers]/10
Annex K of the C standard describes a large number of functions, with associated types and macros, which “promote safer, more secure programming” than many of the traditional C library functions. The names of the functions have a suffix of _s; most of them provide the same service as the C library function with the unsuffixed name, but generally take an additional argument whose value is the size of the result array. If any C++ header is included, it is implementation-defined whether any of these names is declared in the global namespace. (None of them is declared in namespace std.)
Emphasis mine
and table 18 list localtime_s as a member so, because of the above section, we know that it is not defined in namespace std and if it does exist it will be in the global namespace. Try using
::localtime_s(&tm, &time);
and if that still does not work it means your implementation does not support it.
Related
An old method contains code like the following (anonymised):
std::wstring wstr = ...;
std::string str(wstr.begin(), wstr.end());
Previously this all compiled without warnings but as we update to C++17 and VS2019 (v142) and tidy project settings, it now gives these big scary warnings:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2468,23): warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem', possible loss of data
with
[
_Elem=char
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2479): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(_Iter,const _Iter,std::input_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29333\include\xstring(2459): message : see reference to function template instantiation 'void std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Construct<wchar_t*>(const _Iter,const _Iter,std::forward_iterator_tag)' being compiled
with
[
_Iter=wchar_t *
]
message : see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>,0>(_Iter,_Iter,const _Alloc &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
message : see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>,0>(_Iter,_Iter,const _Alloc &)' being compiled
with
[
_Elem=wchar_t,
_Iter=std::_String_iterator<std::_String_val<std::_Simple_types<wchar_t>>>,
_Alloc=std::allocator<char>
]
I am pretty sure this code pre-dates use of UNICODE in our codebase - it seems to work but I don't really understand the warnings or what I should do about it.
I found this question: UTF8 to/from wide char conversion in STL but the nice neat solution has comments saying it's deprecated in C++17! It's somewhat a mystery why this code mixes string and wstring in the first place, is there an easy solution? Or is this a case "just leave it if it works?!"
The issue is that you are converting from a 16 bit string to an 8 bit string. Since 16 bits hold more data than 8, data will then get lost. If you are converting between UTF-16 and UTF-8, you need to do it properly with a conversion library.
C++ does provide conversion library in the form of: codecvt (Deprecated in C++17 but still there for a while).
If you are sure the string only contains ASCII, you can suppress the warning.
See https://en.cppreference.com/w/cpp/locale/codecvt_utf8_utf16 for details
The warning is quite clear on its own.
warning C4244: 'argument': conversion from 'wchar_t' to 'const _Elem',
possible loss of data
Which means, this line std::string str(wstr.begin(), wstr.end()) involves a type casting from wchar_t to a narrower data type const _Elem a.k.a char. Since any narrowing cast may lead to data loss, hence the warning.
Consider an example as following:
#include <cstddef>
#include <iostream>
#include <string>
int main() {
std::wstring ws{};
auto c = (wchar_t)0x41'42'43'44; // A'B'C'D in ASCII
for (int i = 0; i < 3; ++i)
ws.push_back(c);
std::string str{ws.begin(), ws.end()};
std::cout << str.c_str() << std::endl;
}
The code above run and print DDD.
On 64 bit machine, the constructor of str move 4 bytes at a time to read a wchar_t. However, string type can only accept element as char ==> the constructor must perform a narrowing cast from wchar_t to char which results in a loss of 3 byte A B C for each wchar_t element.
i have Microsoft Visual Studio (MSVS) 2012 Pro and i have set warning level to a slightly elevated level of 4. when doing this i am getting warnings for some of the included header files from the boost library. the message is this:
C:\Users\****\boost/optional/optional.hpp(595): warning C4244: 'initializing' : conversion from 'T_DOUBLE' to 'float', possible loss of data
C:\Users\****\boost/optional/optional.hpp(430) : see reference to function template instantiation 'void boost::optional_detail::optional_base<T>::construct<double>(Expr &&,const void *)' being compiled
with
[
T=T_FLOAT,
Expr=T_DOUBLE
]
C:\Users\****\boost/optional/optional.hpp(430) : see reference to function template instantiation 'void boost::optional_detail::optional_base<T>::construct<double>(Expr &&,const void *)' being compiled
with
[
T=T_FLOAT,
Expr=T_DOUBLE
]
the code in the file leading to this warning is this (line 610 on most recent beta of boost 1.64.0.B2 still resembles it exactly - but i am not on the beta now):
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Constructs using any expression implicitly convertible to the single argument
// of a one-argument T constructor.
// Converting constructions of optional<T> from optional<U> uses this function with
// 'Expr' being of type 'U' and relying on a converting constructor of T from U.
template<class Expr>
void construct ( Expr&& expr, void const* )
{
new (m_storage.address()) value_type(boost::forward<Expr>(expr)) ;
m_initialized = true ;
}
what is the reason (=learn to understand) for this warning and how to eliminate it in the boost header for me any anyone else? alternatively thinking: does it make sense to "fix" it in such a global way, or is there a deeper meaning pointing rather to somewhere else (either boost or application codes) to improve or fix those other codes?
You are probably passing a double literal into method that expects float. Something like foo(1.0) instead of foo(1.0f)
The following program
#include <ctime>
struct clock {};
int main() {
clock c;
}
fails to compile on both g++ 5.4 and clang 3.8 (Ubuntu 64-bit).
g++ output
clock.cpp: In function ‘int main()’:
clock.cpp:6:11: error: expected ‘;’ before ‘c’
clock c;
^
clang output
clock.cpp:6:5: error: must use 'struct' tag to refer to type 'clock' in this scope
clock c;
^
struct
/usr/include/time.h:189:16: note: struct 'clock' is hidden by a non-type declaration of 'clock' here
extern clock_t clock (void) __THROW;
^
1 error generated.
The diagnostics vary a little in form, but are related to the same issue. There is a clash with the standard C function clock and the struct of the same name defined in the program. The relevant declaration from time.h:
extern clock_t clock (void) __THROW;
The question is: shouldn't such symbols be in the std namespace, since the program includes <ctime>? Interestingly, that very declaration sits a couple of lines after a macro which reads __BEGIN_NAMESPACE_STD. In addition, in <ctime>, one can see:
namespace std
{
using ::clock_t;
using ::time_t;
using ::tm;
using ::clock;
...
}
Is there some kind of bug here?
Thank you.
The question is: shouldn't such symbols be in the std namespace...
Yes, and they are. Unfortunately, the C++ standard also allows implementations to put names from C-library derived headers in the global namespace. In this case, you get std::clock and ::clock.
This applies to all the <c*> C++ headers with a corresponding <*.h> version in C.
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.
I tried a simple example with boost::function. However I got the compiler error said:
#include <boost/array.hpp>
#include <boost/function.hpp>
#include <iostream>
float div( float x, float y ) {
return x / y;
}
int main() {
boost::function<float (float x, float y)> f;
f = ÷
std::cout << f( 3.0f, 3.5f ) << "\n";
}
Error:
Error 2 error C2568: '=' : unable to resolve function overload c:\visual studio 2010 projects\net report\net report\main.cpp 12 1 NET Report
Error 1 error C2563: mismatch in formal parameter list c:\visual studio 2010 projects\net report\net report\main.cpp 12 1 NET Report
Any idea?
Thanks,
Chan
What follows the error is actually quite interesting :
1> e:[...]\main.cpp(11): error C2568: '=' : unable to resolve function overload
1> e:[...]\main.cpp(5): could be 'float div(float,float)'
1> d:\microsoft visual studio 10.0\vc\include\stdlib.h(479): or 'lldiv_t div(_int64,_int64)'
1> d:\microsoft visual studio 10.0\vc\include\stdlib.h(475): or 'ldiv_t div(long,long)'
1> d:\microsoft visual studio 10.0\vc\include\stdlib.h(432): or 'div_t div(int,int)'
There are multiple functions named div in scope (coming from stdlib.h), and the compiler does not know which one you are referring to when you write &div, either :
use a cast : f = static_cast<float (*)(float, float)>(&div);
put your div function in a separate namespace : f = &my_namespace::div
div is the name of a C Standard Library function in <stdlib.h>. Visual C++ has included this header (probably in <iostream>), hence there is an ambiguity.
You can fix it by using a cast:
f = (float(*)(float, float))÷
Note that it shouldn't put these functions into the global namespace; it should include <cstdlib> instead where they should only be in namespace std (even in that header they are also declared in the global namespace, which is wrong, but is common and is the current state of affairs that we have to live with).