Unusual behavior of standard library function abs() on different C++ compilers - c++

Consider following program:
#include <cstdio>
#include <cmath>
int main()
{
int d = (int)(abs(0.6) + 0.5);
printf("%d", d);
return 0;
}
g++ 7.2.0 Output 0 ( See live demo here )
g++ 6.3.0 ( See live demo here )
prog.cc: In function 'int main()':
prog.cc:6:26: error: 'abs' was not declared in this scope
int d = (int)(abs(0.6) + 0.5);
^
prog.cc:6:26: note: suggested alternative:
In file included from prog.cc:2:0:
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/cmath:103:5: note: 'std::abs'
abs(_Tp __x)
^~~
clang++ 5.0.0 Output 1 ( See live demo here )
clang++ 3.6.0 ( See live demo here )
prog.cc:6:19: error: use of undeclared identifier 'abs'; did you mean 'fabs'?
int d = (int)(abs(0.6) + 0.5);
^~~
fabs
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:181:14: note: 'fabs' declared here
__MATHCALLX (fabs,, (_Mdouble_ __x), (__const__));
^
/usr/include/math.h:71:26: note: expanded from macro '__MATHCALLX'
__MATHDECLX (_Mdouble_,function,suffix, args, attrib)
^
/usr/include/math.h:73:22: note: expanded from macro '__MATHDECLX'
__MATHDECL_1(type, function,suffix, args) __attribute__ (attrib); \
^
/usr/include/math.h:76:31: note: expanded from macro '__MATHDECL_1'
extern type __MATH_PRECNAME(function,suffix) args __THROW
^
/usr/include/math.h:79:42: note: expanded from macro '__MATH_PRECNAME'
#define __MATH_PRECNAME(name,r) __CONCAT(name,r)
^
/usr/include/x86_64-linux-gnu/sys/cdefs.h:88:23: note: expanded from macro '__CONCAT'
#define __CONCAT(x,y) x ## y
^
1 error generated.
Microsoft VC++ 19.00.23506 Output 1 ( See live demo here )
What exactly is happening here in this program ? Why it gives different output when compiled on different C++ compilers ? Why program exhibits different behavior even on different version of same compiler ? Is this compiler issue or standard library (libstdc++ & libc++) issue ? What C++ standard says about this ?
P.S: I know that I need to write std::abs instead of abs. But this is not my question.

All the cname library headers that bring in functionality from the C standard library must introduce those symbols in namespace std. They also may, but definitely not must introduce them into the global namesapce. [headers]/4:
Except as noted in Clauses [library] through [thread] and Annex
[depr], the contents of each header cname is the same as that of the
corresponding header name.h as specified in the C standard library. In
the C++ standard library, however, the declarations (except for names
which are defined as macros in C) are within namespace scope of the
namespace std. It is unspecified whether these names (including any
overloads added in Clauses [language.support] through [thread] and
Annex [depr]) are first declared within the global namespace scope and
are then injected into namespace std by explicit using-declarations.
So different compilers, and even different compiler versions, mean different implementation details.

Related

Which header file or definitions to use for using char8_t data type in C++?

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.

What is the correct way to call std::to_chars?

I am trying to call std::to_chars on a double. My code doesn't compile on any compiler I have (gcc 10.2, clang 10.0.1).
Minimally reproducible code (or on godbolt):
#include <charconv>
#include <string>
int main() {
std::string str;
str.resize(30);
auto[ptr, ec] = std::to_chars(str.data(), str.data() + str.size(), double(3.5));
}
I compiled with -std=c++17.
The error I'm getting is:
On gcc 10.2:
<source>: In function 'int main()':
<source>:7:83: error: call of overloaded 'to_chars(char*, char*, double)' is ambiguous
7 | auto[ptr, ec] = std::to_chars(str.data(), str.data() + str.size(), double(3.5));
| ^
In file included from <source>:1:
/.../gcc-10.2.0/include/c++/10.2.0/charconv:366:1: note: candidate: 'std::to_chars_result std::to_chars(char*, char*, char, int)'
...
and then it lists all candidates.
On clang 10.0.1, it pretty much just tells me:
<source>:7:21: error: no matching function for call to 'to_chars'
auto[ptr, ec] = std::to_chars(str.data(), str.data() + str.size(), double(3.5));
^~~~~~~~~~~~~
I tried all the overloads with double that are listed on cppreference's page on std::to_chars, they all give different errors, but in the end nothing works.
I do not understand why the overload resolution is not clear when it should be clear, or am I doing something fundamentally wrong here?
I want to add that MSVC does it fine without any errors.
Your use is perfectly fine, and it compiles correctly under MSVC 19. As described in the Microsoft Docs for the <charconv> functions, this requires at least C++17.
As you can see for yourself in The GNU C++ Library Manual, Chapter 1. Status, C++ 2017, the last update regarding P0067R5 (Elementary string conversions, revision 5) was on GCC 8.1, with the comment "only integral types supported".
Similarly, the libc++ C++17 Status, defines P0067R5 as "Partially done".
If you need more evidence that this is a problem with your C++ implementation, look at the include file for your GCC/Clang installation and you will see that it doesn't define the floating-point overloads (they aren't defined for me, with GCC 10.2.1).

Permitted usage context of declarations

The following code
#include <iostream>
#include <memory>
#include <ios>
using std::cout;
using std::endl;
using std::unique_ptr;
using std::make_unique;
using std::boolalpha;
template<typename T>
struct alloc{
alloc();
unique_ptr<T> operator() (void){
return(auto up = make_unique<T>(NULL));
}
};
int main (void){
auto up = alloc<int>()();
cout << boolalpha << ((up) ? 1 : 0) << endl;
return 0;
}
when compiled gives the following error:
g++ -ggdb -std=c++17 -Wall -Werror=pedantic -Wextra -c code.cpp
code.cpp: In member function ‘std::unique_ptr<_Tp> alloc<T>::operator()()’:
code.cpp:14:16: error: expected primary-expression before ‘auto’
return(auto up = make_unique<T>(NULL));
^~~~
code.cpp:14:16: error: expected ‘)’ before ‘auto’
make: *** [makefile:20: code.o] Error 1
There is an earlier question on SO reporting the same error:
C++17 std::optional error: expected primary-expression before 'auto'
The following is a snippet from the accepted answer to the above question:
Declarations are not expressions. There are places where expressions
are allowed, but declararions are not.
So my questions based on the compilation error I get are:
a) Is the use of a declaration in a return statement not permitted by the standard?
b) What are the permitted contexts for declarations?
Note: I had deliberately used the auto keyword in the return statement to reproduce this error. This error had originally appeared in a larger code base.
TIA
Is the use of a declaration in a return statement not permitted by the standard?
Indeed it isn't. We need only examine the grammar production at [stmt.jump]/1
Jump statements unconditionally transfer control.
jump-statement:
break ;
continue ;
return expr-or-braced-init-listopt ;
goto identifier ;
There is no production that turns an "expr-or-braced-init-list" into any sort of statement, so no declaration statement either. There is also no production that turns it into any other sort of declaration (such as a function, namespace or class). So you cannot declare anything in the return statement's operand.
What are the permitted contexts for declarations?
Almost anywhere an expression isn't required explicitly. The very definition of a translation unit in C++ (one file being translated) is a sequence of declarations per [basic.link]/1.
A program consists of one or more translation units linked together. A
translation unit consists of a sequence of declarations.
translation-unit:
declaration-seqopt
Different declarations have different structure. Somes such as namespaces, may contain more declarations. Others such as functions may contain statements, which themselves may be declaration statements of certain things. But most importantly, the standard makes clear where a statement may appear, and where only an expression is permitted.

Clash with identifier 'clock' from time.h

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.

Wait() in process creation

The following is my code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
using namespace std;
int main() {
int cpid=fork();
if(cpid==0) {
printf("%d %d\n",getpid(),getppid());
}
else {
printf("hello");
wait(NULL);
}
}
When I compile this using the following:
g++ -std=c++11 multiple.cpp -o multiple
It gives me the following
multiple.cpp: In function 'int main()':
multiple.cpp:34:23: error: no matching function for call to 'wait::wait(NULL)'
wait(NULL);
^
multiple.cpp:34:23: note: candidates are:
In file included from /usr/include/stdlib.h:42:0,
from multiple.cpp:4:
/usr/include/bits/waitstatus.h:66:7: note: wait::wait()
union wait
/usr/include/bits/waitstatus.h:66:7: note: candidate expects 0 arguments, 1 provided
/usr/include/bits/waitstatus.h:66:7: note: constexpr wait::wait(const wait&)
/usr/include/bits/waitstatus.h:66:7: note: no known conversion for argument 1 from 'int' to 'const wait&'
/usr/include/bits/waitstatus.h:66:7: note: constexpr wait::wait(wait&&)
/usr/include/bits/waitstatus.h:66:7: note: no known conversion for argument 1 from 'int' to 'wait&&'
But if I change the extension to .c and use gcc -o multiple multiple.c it works. Why is this happening?
You have not included the correct header file that the wait() documentation tells you need.
You need
#include <sys/wait.h>
Because wait is declared in sys/wait.h, which you do not include, and C++ requires all the functions to be prototyped before used. C, on the other hand, does not.
You did not include the header for the POSIX wait function, per the documentation:
#include <sys/wait.h>
It is surprising but not inconceivable that the equivalent standard library headers in your C toolchain just so happen to include this themselves, whereas the C++ ones you have used do not.
More likely, you are inadvertently making use of the terrible rule in C that says you can use some functions before they have been declared.