std::expf and std::logf not recognized by gcc 7.2.0 - c++11

It seems that gcc (tried 7.2.0 and 5.4.0) does not have std::expf and std::logf - see coliru sample. Since cppreference says they were added in C++11 is there some gcc specific macro I am missing or are they in general missing in gcc?

This is a bug in libstdc++, which ships with GCC. It does not fully conform to C++17 (as of v9.1.0 in June 2019). The copyright notice on the version of <cmath> that Ubuntu uses by default says it was last updated in 2016. Version 9.1.0 does have a #if __cplusplus > 201402L section, but it doesn’t declare the identifiers required by C++17. There is an open bug report.
It never declares expf or logf (nor cosf, sinf, etc.) within the std:: namespace, even though C++17 says it shall. The C++11 standard says, “Names that are defined as functions in C shall be defined as functions in the C++ standard library,” and “Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.” However, std::expf et al. are missing from the table of functions provided by <cmath> until P0175r1 in June 2016. This was apparently an oversight, but GCC has always made them available only in the global namespace.
The libc++ library does declare them, so compiling with clang++ -std=c++17 -stdlib=libc++ should work. You can also #include <math.h> to use them in the global namespace, or use the overloaded exp(), log(), etc. on float arguments.

If you
#include <cmath>
you will get
float exp ( float arg );
double exp ( double arg );
long double exp ( long double arg );
double exp ( IntegralType arg );
float log ( float arg );
double log ( double arg );
long double log ( long double arg );
double log ( IntegralType arg );
And hence you can call just std::exp/std::log and let the compiler figure out the overload for you. If you want to call a mismatching overload (e.g. the float overload on a double variable), I find it much more explicit and clear to add a static_cast in those cases:
double bla = ...;
return std::exp(static_cast<float>(bla));
This is a strange construct any way you write it (e.g. why is bla not a float to begin with?), and hiding it in a single-letter function name suffix isn't helping anyone.

GCC's <cmath> declares the functions expf and logf and their C Library kin in the
global namespace, not std::. In std:: it declares overloads of exp and log to
the same effect.

Related

What is the difference between crypt in unistd.h and crypt.h?

Background
crypt has two definitions, from the docs,
One of them uses unistd.h
#define _XOPEN_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
This is defined as
#ifdef __USE_MISC
extern char *crypt (const char *__key, const char *__salt)
__THROW __nonnull ((1, 2));
#endif
One of them uses GNU crypt.h
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <crypt.h>
This is defined as
extern char *crypt (const char *__phrase, const char *__salt)
__THROW __nonnull ((1, 2));
Problem
When I compile with the definition in the first example (unistd.h)
#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
int main()
{
printf("%s", crypt("foobar", "sa"));
}
I'm getting the error
In function ‘main’:
warning: implicit declaration of function ‘crypt’; did you mean ‘chroot’? [-Wimplicit-function-declaration]
printf("%s", crypt("foobar", "sa"));
^~~~~
chroot
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("%s", crypt("foobar", "sa"));
~^ ~~~~~~~~~~~~~~~~~~~~~
%d
Out of desperation, I've tried adding this.
#define _XOPEN_VERSION 700
#define _POSIX_VERSION 200809L
#define __USE_MISC 1
On Ubuntu Trusty 14.04 I believe this works fine use the unistd.h declaration, which makes all the more confusing.
These are two declarations, not two definitions. The content of the header file has no impact on which definition of a function is included: this is determined by the linker. There is only one definition of the crypt function in the Unix C standard library, it's whatever the symbol crypt points to in libcrypt.a or libcrypt.so (depending on whether you link statically or dynamically).
Since the two declarations are compatible, it doesn't matter which header a program gets its through. It's also fine if both declarations are processed: a program can contain any number of declarations for a function as long as they're compatible. Without going into the exact details (refer to the C language specification), two function declarations are compatible if they have the same return type, the same number of arguments and the same type for each argument. The name of the argument given in a declaration is not significant.
You should ignore unistd.h. That declaration is there for POSIX compatibility but GLIB has removed the definition for crypt when they migrated to libxcrypt to develop those features in isolation of glibc. This means you can still get ABI-compatibility but must link in the crypt. You can read more about that here
Availability in glibc
The crypt (), encrypt (), and setkey () functions are part of the POSIX.1-2008 XSI Options Group for Encryption and are optional. If the interfaces are not available then the symbolic constant _XOPEN_CRYPT is either not defined or defined to -1, and can be checked at runtime with sysconf ().
This may be the case if the downstream distribution has switched from glibc crypt to libxcrypt. When recompiling applications in such distributions the
user must detect if _XOPEN_CRPYT is not available and include crypt.h for the function prototypes; otherwise libxcrypt is a ABI compatible drop-in replacement.
As for why even if you link the definition isn't pulled down with
#define _XOPEN_VERSION 700
#define _POSIX_VERSION 200809L
#define __USE_MISC 1
#define _XOPEN_SOURCE
Well there are a few things that happening there
The only header that matters in unistd.h is __USE_MISC.
unistd.h includes features.h which undefs the __USE_ macros to start with a "clean slate"
The only way to define __USE_MISC is to have defined _GNU_SOURCE.
If you want to pull in the declaration of crypt.h from unistd.h you must define _GNU_SOURCE! Those two examples cited from man page of crypt.h do the same thing and whether you include unistd.h or crypt.h you MUST also define _GNU_SOURCE in contemporary versions of glibc.
So you can either do,
#define _GNU_SOURCE
#include <unistd.h>
Or,
#define _GNU_SOURCE
#include <crypt.h>
But because you must link against crypt (-lcrypt) I would suggest using the declaration in crypt.h for sanity.

Can't locate the undefined reference to an extern variable (dev c++)

(Apologies if it is simple, and I am simply being blind.)
main.cpp:
#include "a.h"
int main()
{
x = 4 ;
}
a.h:
extern int x ;
(For some reason this code worked during the first compilation, but not the second one.
Side question: Occasionally I have problems where I need to compile a code twice for it to work. Do I have compiler issues?)
As you know, building a C or C++ program involves three steps: preprocessing, compiling and linking. Here is a simple, non-technical description of what happens.
Preprocessing
The preprocessor will replace the #include "a.h" with the verbatim contents of the file a.h. This results in
extern int x;
int main()
{
x = 4;
}
Compiling
The compiler processes the output of the preprocessor. The extern int x; is a declaration only, not a definition. It tells the compiler that it can trust that somewhere else space is reserved for a variable called x of type int. (extern x means that x has so-called external linkage.) The compiler generates code to set this variable to 4, but marks the code to ask the linker to fill in the actual location of x once the linker has determined where it is defined.
Linking
The linker processes the object file generated by the compiler in the previous step. It looks for an actual definition of x but finds none (x was only declared but never defined) and issues an undefined symbol error.
If you want to see extern in action, simply create a third file, say b.cpp:
// b.cpp
int x;
If you now build a program consisting of main.cpp and b.cpp, the linker error disappears. b.cpp defines x, so the linker will pick up this definition and fill in the location of x in the placeholder code generated by the compilation of main.cpp where it gets set to 4.
As for the side question: I think your issue where compilation sometimes succeeds and sometimes not is likely due to some mistake on the operator's part :-)

error: taking address of temporary [-fpermissive] while compiling &(int) {}

I discovered few days ago Compound literals in the answer How do I use setsockopt(SO_REUSEADDR)?
So I tried to compile simple code :
#include <stdio.h>
int main()
{
int * ptr = &(int) {3};
printf("%d\n", *ptr);
return 0;
}
Using gcc 4.9.1, it build and works as expected, it print "3" and valgrind doesnot report memory corruption.
However using g++ 4.9.1, it does not build :
$ g++ main.c
main.c: In function ‘int main()’:
main.c:4:23: error: taking address of temporary [-fpermissive]
int * ptr = &(int) {3};
^
Is there is a way (like an g++ option) to support Compound literal ?
In C language compound literals are lvalues. It is perfectly legal to take address of a compound literal in C. In C a local compound literal lives to the end of its enclosing block.
Meanwhile, GCC brings over compound literals to C++ (as a non-standard extension) with a number of significant changes. They are brought over as temporary objects. It is illegal to take address of a temporary object in C++. The lifetime of compound literals in C++ is also consistent with lifetime of temporaries - they live to the end of the expression.
AFAIK, there's no way to make GCC's C++ compound literals to behave as their C counterparts.

gcc optimizations: how to deal with macro expantion in strncmp & other functions

Take this sample code:
#include <string.h>
#define STRcommaLEN(str) (str), (sizeof(str)-1)
int main() {
const char * b = "string2";
const char * c = "string3";
strncmp(b, STRcommaLEN(c));
}
If you don't use optimizations in GCC, all is fine, but if you add -O1 and above, as in gcc -E -std=gnu99 -Wall -Wextra -c -I/usr/local/include -O1 sample.c, strncmp becomes a macro, and in preprocessing stage STRcommaLen is not expanded. In fact in resulting "code" strncmp's arguments are completely stripped.
I know if I add #define NEWstrncmp(a, b) strncmp (a, b) and use it instead, the problem goes away. However, mapping your own functions to every standard function that may become a macro doesn't seem like a great solution.
I tried finding the specific optimization that is responsible for it and failed. In fact if I replace -O1 with all the flags that it enables according to man gcc, the problem goes away. My conclusion is that -O1 adds some optimizations that are not controlled by flags and this is one of them.
How would you deal with this issue in a generic way? There may be some macro magic I am not familiar with or compiler flags I haven't looked at? We have many macros and a substantial code base - this code is just written to demonstrate one example.
Btw, GCC version/platform is gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5).
Thanks,
Alen
You correctly noted that
in preprocessing stage STRcommaLen is not expanded
- more precisely, not before the strncmp macro gets expanded. This inevitably leads to an error you probably overlooked or forgot to mention:
sample.c:7:30: error: macro "strncmp" requires 3 arguments, but only 2 given
Your conclusion
that -O1 adds some optimizations that are not controlled by flags and
this is one of them
is also right - this is controlled by the macro __OPTIMIZE__ which apparently gets set by -O1.
If I'd do something like that (which I probably wouldn't, in respect of the pitfall you demonstrated by using sizeof a char *), I'd still choose
mapping your own functions to every standard function that may become
a macro
- but rather like
#include <string.h>
#define STRNCMP(s1, s2) strncmp(s1, s2, sizeof(s2)-1)
int main()
{
const char b[] = "string2";
const char c[] = "string3";
STRNCMP(b, c);
}

strdup error on g++ with c++0x

I have some C++0x code. I was able to reproduce it below. The code below works fine without -std=c++0x however i need it for my real code.
How do i include strdup in C++0x? with gcc 4.5.2
note i am using mingw. i tried including cstdlib, cstring, string.h and tried using std::. No luck.
>g++ -std=c++0x a.cpp
a.cpp: In function 'int main()':
a.cpp:4:11: error: 'strdup' was not declared in this scope
code:
#include <string.h>
int main()
{
strdup("");
return 0;
}
-std=gnu++0x (instead of -std=c++0x) does the trick for me; -D_GNU_SOURCE didn't work (I tried with a cross-compiler, but perhaps it works with other kinds of g++).
It appears that the default (no -std=... passed) is "GNU C++" and not "strict standard C++", so the flag for "don't change anything except for upgrading to C++11" is -std=gnu++0x, not -std=c++0x; the latter means "upgrade to C++11 and be stricter than by default".
strdup may not be included in the library you are linking against (you mentioned mingw). I'm not sure if it's in c++0x or not; I know it's not in earlier versions of C/C++ standards.
It's a very simple function, and you could just include it in your program (though it's not legal to call it simply "strdup" since all names beginning with "str" and a lowercase letter are reserved for implementation extensions.)
char *my_strdup(const char *str) {
size_t len = strlen(str);
char *x = (char *)malloc(len+1); /* 1 for the null terminator */
if(!x) return NULL; /* malloc could not allocate memory */
memcpy(x,str,len+1); /* copy the string into the new buffer */
return x;
}
This page explains that strdup is conforming, among others, to the POSIX and BSD standards, and that GNU extensions implement it. Maybe if you compile your code with "-D_GNU_SOURCE" it works?
EDIT: just to expand a bit, you probably do not need anything else than including cstring on a POSIX system. But you are using GCC on Windows, which is not POSIX, so you need the extra definition to enable strdup.
add this preprocessor "_CRT_NONSTDC_NO_DEPRECATE" to Project Properties->C/C++ Build->GCC C++ Compiler->Preprocessor->Tool Settings
Don't forget to check Preprocessor Only(-E)
This worked for me on windows mingw32.

Resources