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.
Related
Not including the #ifndef guard to prevent multiple header file inclusions, does not throw compile error. Why is that?
// main.c
#include <stdio.h>
#include "declare.h"
#include "declare.h" //Shouldn't I get compiler error here
int main(){
printf("Hello World\n");
}
// declare.h
#define a 1 //just this define in declare.h file
Command used to compile: gcc main.c -std=c89
Including a header multiple times is not an error, either with or without guards.
Guards prevent you from redefining objects and functions, when you do so.
But you haven't done that. You've just redefined a macro with the same value it had before. Which is fine.
You can test this by just compiling the following file:
#define a 1
#define a 1
It's fine.
[C89: 6.8.3]: [..] An identifier currently defined as a macro without use of lparen (an object-like macro) may be redefined by another #define preprocessing directive provided that the second definition is an object-like macro definition and the two replacement lists are identical. [..]
Start putting more complex stuff in that header and you'll see a problem.
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.
I am writing a code using other packages in C languages and some in C++ langauges. So my code, needs to work with C routines, and C++ classes as well. My plan is, to include all the header files in C with extern "C" {} method and use g++ to compile.
So, I copied all the headers in C to a directory and added headers and footers like,
#ifdef __cplusplus
extern "C" {
#endif
//...
#ifdef __cplusplus
}
#endif
However, it still doesn't compile. So I made a mock C program to make it look clear how the problem shows up.
main.C
#include <stdio.h>
#include <A.h> //This is the problematic header file.
int main()
{
struct MMM m; //some struct in A.h
printf("How many times do I have to compile this? %d\n",1000);
return 0;
}
A.h
#ifndef _A_H
#define _A_H
#ifndef ...
#define ... ...
#endif
#include <B.h>
#include <C.h>
#endif
And it gives me the same error messages while compiling the mock program as the ones during compilation of the real code I was working on. And it is about some preprocessor macro functions defined in B.h and C.h. But I want to assure you all these header files are written inside extern "C" {}. Mock program is written in C language only so I was able to check there is no error messages with gcc and it works great.
So what I am wondering is, doesn't the g++ with extern "C" work just as gcc? Or did I miss something? Is there any suggestions to go around this problem?
extern "C" does not turn a C++ compiler into a C compiler. The code still has to be valid C++ code. It cannot use new keywords as identifiers, there is no implicit cast from void * to other pointer types, and so on. extern "C" only affects linkage (basically, how the code interacts with other translation units). It does not change the source language the compiler accepts.
The C preprocessor macro for concatenation (##) does not seem to work on a Mac using gfortran. Using other Fortran compilers on other systems works so I am looking for a workaround for gfortran. I have to use the ## to create many variables so I can't do without them.
Example code:
#define CONCAT(x,y) x##y
program main
integer, parameter:: CONCAT(ID,2) = 3
print*,"Hello", ID_2
end program main
Compilation error with gfortran on MAC
gfortran m.F90 -o m
m.F90:5.23:
integer, parameter:: ID##2 = 3
1
Error: PARAMETER at (1) is missing an initializer
## doesn't work in gfortran (any OS, not just Mac) because it runs CPP in the traditional mode.
According to this thread the gfortran mailing list the correct operator in the traditional mode is x/**/y, so you must distinguish between different compilers:
#ifdef __GFORTRAN__
#define CONCAT(x,y) x/**/y
#else
#define CONCAT(x,y) x ## y
#endif
Others (http://c-faq.com/cpp/oldpaste.html) use this form, which behaves better when a macro passed to the CONCAT (via Concatenating an expanded macro and a word using the Fortran preprocessor):
#ifdef __GFORTRAN__
#define PASTE(a) a
#define CONCAT(a,b) PASTE(a)b
#else
#define PASTE(a) a ## b
#define CONCAT(a,b) PASTE(a,b)
#endif
The indirect formulation helps to expand the passed macro before the strings are concatenated (it is too late after).
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);
}