I understand that the config.h header file should be considered to be an internal header file. Now I wonder how to publish something that depends on config.h settings without publishing the config.h itself.
Say, I have a public function returning bool, i.e. depending on either stdbool.h or any appropriate definition of bool. It should be declared within a public header, but this header may be used in an environment without stdbool.h and maybe even without config.h or with a config.h saying nothing about the presence of bool.
I came up with an unsatisfactory solution like this:
#if HAVE_STDBOOL_H || !HAVE_CONFIG_H
# include <stdbool.h>
#endif
#if !__bool_true_false_are_defined
# if !HAVE__BOOL
typedef int _Bool;
# endif
typedef _Bool bool;
# define true (bool)1
# define false (bool)0
#endif
extern bool public_bool(void);
This should work in most standard cases but may fail in many others.
Maybe it's obsolete taking environments without stdbool.h into consideration at all today (I don't know), but this is just a sample of my comprehension gap concerning the autotool-thing. What is the best practice to deal with the problem in general?
In the specific case of <stdbool.h>, we chose to avoid depending on config.h and to rely on the C (or C++) compiler to tell us what is OK. The code includes this header, and this header sorts out the mess. It is known to work on Mac OS X, Linux, Solaris, HP-UX, AIX, Windows. The actual header file name is not ourbool.h, but I've mangled its header guards and comments so it looks as if that is what it is called. The comments quote the C99 standard for the licence to perform as it does. Note that it also works correctly if <stdbool.h> has already been included, and it works correctly if <stdbool.h> is included after it has been included (and getting this correct was not 100% pain-free). Defining __bool_true_false_are_defined is crucial to this inter-working. (When your code is in use by other people, you can't mandate that they do not use <stdbool.h> themselves, either before or after your header is included.)
#ifndef OURBOOL_H_INCLUDED
#define OURBOOL_H_INCLUDED
/*
** Ensure that type bool with constants false = 0 and true = 1 are defined.
** C++ (ISO/IEC 14882:1998/2003/2011) has bool, true and false intrinsically.
** C (ISO/IEC 9899:1999) has bool, true and false by including <stdbool.h>
** C99 <stdbool.h> also defines __bool_true_false_are_defined when included
** MacOS X <dlfcn.h> manages to include <stdbool.h> when compiling without
** -std=c89 or -std=c99 or -std=gnu89 or -std=gnu99 (and __STDC_VERSION__
** is not then 199901L or later), so check the test macro before defining
** bool, true, false. Tested on MacOS X Lion (10.7.1) and Leopard (10.5.2)
** with both:
** #include "ourbool.h"
** #include <stdbool.h>
** and:
** #include <stdbool.h>
** #include "ourbool.h"
**
** C99 (ISO/IEC 9899:1999) says:
**
** 7.16 Boolean type and values <stdbool.h>
** 1 The header <stdbool.h> defines four macros.
** 2 The macro
** bool
** expands to _Bool.
** 3 The remaining three macros are suitable for use in #if preprocessing
** directives. They are
** true
** which expands to the integer constant 1,
** false
** which expands to the integer constant 0, and
** __bool_true_false_are_defined
** which expands to the integer constant 1.
** 4 Notwithstanding the provisions of 7.1.3, a program may undefine and
** perhaps then redefine the macros bool, true, and false.213)
**
** 213) See 'future library directions' (7.26.7).
**
** 7.26.7 Boolean type and values <stdbool.h>
** 1 The ability to undefine and perhaps then redefine the macros bool, true,
** and false is an obsolescent feature.
**
** Use 'unsigned char' instead of _Bool because the compiler does not claim
** to support _Bool. This takes advantage of the license of paragraph 4.
*/
#if !defined(__cplusplus)
#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#elif !defined(__bool_true_false_are_defined)
#undef bool
#undef false
#undef true
#define bool unsigned char
#define false 0
#define true 1
#define __bool_true_false_are_defined 1
#endif
#endif /* !_cplusplus */
#endif /* OURBOOL_H_INCLUDED */
Clearly, if you want to allow for the possibility of HAVE_STDBOOL_H, you may, but it is not needed. You can also decide what to do if HAVE_CONFIG_H is defined, but again it is not needed.
To use this, your header would contain:
#ifndef YOURHEADER_H_INCLUDED
#define YOURHEADER_H_INCLUDED
...other #includes as needed...
#include "ourbool.h" /* Or #include "project/ourbool.h" */
...other material...
extern bool boolean_and(bool lhs, bool rhs);
...other material...
#endif /* YOURHEADER_H_INCLUDED */
The precise location of ourbool.h in yourheader.h is not critical as long as it is before you declare types, functions or (perish the thought) variables that use the bool type.
Defining bool, true, and false yourself in a publicly installed header in the event that stdbool.h was not detected at your configure time seems like a very bad idea. In this particular situation, I think the solution is that unless you can assume your library's users will all have conforming C99 or later environments, you shouldn't be using bool as part of the public interface. Using int, like all idiomatic C code does, would make the problem go away entirely.
With that said, there's also a general issue to be addressed that applies in cases not related to bool where there may be a legitimate need for installed headers to behave differently depending on the environment the library was configured for. In that case, I think the best solution is to have your header be a generated file created by your build system (e.g. mylib.h.in with autoconf) that's setup to match the system it's built for.
Related
Suppose that I have the following definitions:
#include <stdbool.h>
#include <stdint.h>
#define ASSERT(cond) _Static_assert(cond, #cond)
typedef union {
struct {
bool bit0:1;
bool bit1:1;
bool bit2:1;
bool bit3:1;
bool bit4:1;
bool bit5:1;
bool bit6:1;
bool bit7:1;
};
uint8_t bits;
} byte;
ASSERT(sizeof(byte) == sizeof(uint8_t));
Is it possible to write a code, such as
#include <assert.h>
// ...
assert(((byte) { .bit0 = 1 }).bits == 0b00000001);
assert(((byte) { .bit1 = 1 }).bits == 0b00000010);
assert(((byte) { .bit2 = 1 }).bits == 0b00000100);
assert(((byte) { .bit3 = 1 }).bits == 0b00001000);
assert(((byte) { .bit4 = 1 }).bits == 0b00010000);
assert(((byte) { .bit5 = 1 }).bits == 0b00100000);
assert(((byte) { .bit6 = 1 }).bits == 0b01000000);
assert(((byte) { .bit7 = 1 }).bits == 0b10000000);
// ...
that would cause a compile-time failure if the above conditions weren't satisfied?
(When I try to place the conditions in the ASSERT macro, the compiler complains that expression in static assertion is not constant, which of course makes perfect sense)
The solution is allowed to use the GNU extensions to the C language.
I don't think you can.
_Static_assert is required to verify that the argument expression satisfies standard C's requirements for an integer constant expression.
There are ways, which on gcc can sometimes turn a boolean expression that doesn't satisfy those requirements but are compile-time-known to the optimizer into a compile-time error or warning.
E.g., :
#include <assert.h>
#if __GNUC__ && !__clang__
#define $SassertIfUCan0(X) \
(__extension__({ /*ellicit a -Wvla-larger-than */ \
(!__builtin_constant_p(X)) ? 0 : \
({ char volatile $SassertIfUCan0_[ (!__builtin_constant_p(X)||(X)) ? 1:-1]; \
$SassertIfUCan0_[0]=0,0;}); \
__auto_type $SassertIfUCan0 = X; \
assert($SassertIfUCan0); \
0; \
}))
#endif
int main(int C, char **V)
{
int x = 0; $SassertIfUCan0(x);
//these also ellicit compile-time errrors:
/*$SassertIfUCan0(C-C);*/
/*$SassertIfUCan0(C*0);*/
}
can turn the nullness of the compile-time known variable x, which isn't technically an integer constant, into a compile/time warning/error
("-Wvla-larger-than").
Unfortunately, the macro doesn't work with every expression and that includes your bitfield-based example.
(I wish compilers had a mechanism for failing compilation if an expression happens to be compile-time known and false.)
So AFAIK, the closest thing you can do is compile-time detect platforms whose ABI is known to guarantee your required bitfield layout:
#if __linux__ && __x86_64__
#elif 0//...
//...
#else
#error "bitfields not known to be little-endian"
#endif
I think, this is an X-Y problem: You are asking about checking the layout of bitfields when you really want to write code that is portable across different implementations of bitfields. So:
If you don't try to communicate your bitfield to another machine, or store it in a file where a different machine may read it, just forget about the implementation detail of how the bits are ordered. Just access them via the bitfield names, and be done with it.
If you need to communicate the structures containing these bitfields, declare a uint8_t and the appropriate set of bit flag constants (#define BIT7 (1u << 7), etc.). Bytes never change value when they are transferred from one machine to another, so myFlags & BIT7 is guaranteed to yield the same result everywhere.
Note that it is important to either use a single byte to store the flags, or handle the problem of endianess explicitly.
On GNU Linux, you might find <features.h> and /usr/x86_64-linux-gnu/include/linux/byteorder/big_endian.h
The solution is allowed to use the GNU extensions to the C language.
With most recent GCC compilers, you could provide your own GCC plugin defining your __your_builtin_endian__ compiler builtin. Notice that some GCC compilers are built without plugin support (e.g. RedHat did that). Check by running gcc -v alone.
Once your plugin defines __your_builtin_endian__, you could use that in static_assert. Or have your plugin define and implement some #pragma MYPLUGIN check endian which would make a compile-time error in some cases.
Do budget a few weeks of fulltime work for such a plugin. It is GCC version specific (not always the same C++ code for a GCC 9 and GCC 10 plugin).
Consider also using autoconf (at least if you do not need any cross-compilation).
Not strickly within the limits of the question, but may provide for more portable solution.
The static assertion has limits to the expressions, and it will NOT be able to evaluate expression from a union.
As an alternative, and assuming the code will be built by a makefile (or equivalent), consider adding a a step to the build to force the condition
static.verify: static_check.c
cc -o static_check static_check.c
./static_check
touch $#
# Make the static.verify dependency for building objects/executable.
a.o: static.verify
Basically, making it a requirement to run the small program 'static_check.c'. The program can produce any required error message. Should exit with non-zero return status to indicate an error.
When I read some code which run on linux and is compiled by gcc, I meet a declaration like that:
void* (*func_name) _((void *buf, int size))
The BGET source code is that:
void bectl _((int (*compact)(bufsize sizereq , int sequence),
void *(*acquire)(bufsize size),
void *(*release)(void *buf),
bufsize pool_incr));
void bectl(compact, acquire, release, pool_incr)
int(*compact) _((bufsize sizereq, int sequence));
void *(*acquire) _((bufsize size));
void (*release) _((void *buf));
bufsize pool_incr;
{
}
The question is that I don't know why add "_" before parameter list.
_ is a macro intended to allow the code to use prototypes (function declarations that specify the types of the parameters) while still being compatible with pre-ANSI compilers that don't support prototypes.
Note that _ is a valid identifier. However, all identifiers starting with _ are reserved for use at file scope, so this is one more reason the code is potentially non-portable.
The code you're reading is apparently BGET, available here. (It would have been helpful to cite the source in your question.) If you look at the bget.h header file (last updated in 1995), you'll see:
#ifndef _
#ifdef PROTOTYPES
#define _(x) x /* If compiler knows prototypes */
#else
#define _(x) () /* It it doesn't */
#endif /* PROTOTYPES */
#endif
Today, 21 years later, there are very few C compilers in use that don't support prototypes, so the need for such macros is largely obsolete. But even the latest ISO C standard, published in 2011, still supports old-style non-prototype functions.
Note that there's nothing in the source that actually defines the PROTOTYPES macro, so if you want to compile the code with prototypes enabled (to get additional compile-time checking), you'll need to manually edit the makefile, changing this:
COPTS = -O
to this:
COPTS = -O -DPROTOTYPES
Even with that change, compilation still fails because of the invalid redeclaration of malloc. The code needs some work to bring it up to modern standards.
I have a file that uses a FLAGS macro from an include that I do not control. What is in FLAGS is not consistent. Occasionally I need to change FLAGS to add a flag to it. Now I know I can't do #define FLAGS FLAGS|MY_FLAG, but I thought if I stored FLAGS in a temporary variable that I could then undefine it and redefine it using the temporary and my flag. For example:
// Assume this next line is what's in the include file
#define FLAGS (1|2|4)
// The rest of this is source, assume compile with -DMOD
#ifdef MOD
#define TEMP (FLAGS|8)
#undef FLAGS
#define FLAGS TEMP
#endif
int main()
{
printf("0x%x\n", FLAGS);
}
And if MOD is defined the error is error: 'FLAGS' was not declared in this scope. I know that I can change all the actual C code that uses FLAGS to instead use FLAGS|MY_FLAG but I was hoping to modify the macro rather than all the code.
Your only real way to do exactly what you are trying to do is to define an additional macro
// Assume this next line is what's in the include file
#define FLAGS_FOR_A (1|2|4)
#define FLAGS FLAGS_FOR_A
// The rest of this is source, assume compile with -DMOD
#ifdef MOD
#undef FLAGS
#define FLAGS ( FLAGS_FOR_A | 8 )
#endif
int main()
{
printf("0x%x\n", FLAGS);
}
Macros just do simple text replacement, computed before runtime
You can do something logically equivalent to #define FLAGS FLAGS|MY_FLAG if you define the macro as modifiable using Boost's "evaluated slots":
#include <boost/preprocessor/slot/slot.hpp>
// define FLAGS as a modifiable macro and create a setter for it
#define FLAGS BOOST_PP_SLOT(1)
#define UPDATE_FLAGS BOOST_PP_ASSIGN_SLOT(1)
int main(void) {
// set the initial value of FLAGS
#define BOOST_PP_VALUE (1|2|4)
#include UPDATE_FLAGS
printf("0x%x\n", FLAGS); // 0x7
// update FLAGS with a new value using the old one
#define BOOST_PP_VALUE (FLAGS|8)
#include UPDATE_FLAGS
printf("0x%x\n", FLAGS); // 0xf
}
Despite being witchcraft, this is completely standard-compliant C, no extensions. Only works for integers.
(It works by taking advantage of something important: macros aren't just expanded into program code, but also need to be expanded to determine whether to follow an #if branch as well. Since #if directives are also capable of evaluating integer math, this is able to expand the actual numeric value and use it to construct a new expansion for the PP_SLOT that doesn't involve a reference to any macro name. This is all hidden behind the #include UPDATE_FLAGS directives.)
Here is my dead simple dummy code:
#include <errno.h>
int main(void)
{
errno_t e;
return 0;
}
Which surprisingly raises this error:
main.c:5:5: error: use of undeclared identifier 'errno_t'
errno_t x;
^
I started to follow the traces: when the compiler sees the <...> inclusions it will first look at /usr/include where of course I found errno.h file. Actually it has a single line in it, besides the license comment, which is:
#include <sys/errno.h>
Now, at /usr/include/sys in errno.h I found the following lines:
#include <sys/cdefs.h>
#if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1
#include <sys/_types/_errno_t.h>
#endif
And at /usr/include/_types in _errno_t.h I found this:
typedef int errno_t;
So it looks like, it is there, and it is an alias of the integer type, and part of the errno.h -- just as it should be.
Then why isn't it included? Why the compiler raises the undeclared identifier error?
Thanks in advance!
RELEVANT INFO:
Compiler:
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)`
Compiler flags:
-std=c11 -I/usr/include/sys -I/usr/local/include
The macro variable __STDC_WANT_LIB_EXT1__ will be defined at /usr/include/sys in cdefs.h in the following lines:
/* If the developer has neither requested a strict language mode nor a version
* of POSIX, turn on functionality provided by __STDC_WANT_LIB_EXT1__ as part
* of __DARWIN_C_FULL.
*/
#if !defined(__STDC_WANT_LIB_EXT1__) && !defined(__STRICT_ANSI__) && __DARWIN_C_LEVEL >= __DARWIN_C_FULL
#define __STDC_WANT_LIB_EXT1__ 1
#endif
UPDATE:
As #PaulR said in the comment section: if I remove the -std=c11 flag, it compiles. Which is just as surprising as the error raised if the flag was included. So I extend this question with a sub-question:
Is not errno_t part of the C11 standard, or why isn't it included, when the standard is specified for the compiler?
errno_t is not a standard type; it's part of the optional (and widely disliked and unsupported) Annex K, included with ISO C11 only because of one particular vendor with a history of ignoring and sabotaging the standard.
Since Annex K defines errno_t as int, the type of the errno object is int, and all error codes are int, simply use int in your programs. It's much more portable than relying on an optional feature which is unlikely to be supported.
I am now read some c code. And is not very clear about the "#define someting" expression.
For example, I saw this code:
typedef enum cairo_path_op {
CAIRO_PATH_OP_MOVE_TO = 0,
CAIRO_PATH_OP_LINE_TO = 1,
CAIRO_PATH_OP_CURVE_TO = 2,
CAIRO_PATH_OP_CLOSE_PATH = 3
} __attribute__ ((packed)) cairo_path_op_t; /* Don't want 32 bits if we can avoid it. */
#ifndef __GNUC__
#define __attribute__(x)
#endif
I take attention to the "__attribute__(x)". since in other header file , the "__attribute__(x)" is defined with no value, but how it take effect in the enum "cairo_path_op" define?
This is for portability reasons.
__attribute__() is a GCC extension for modifying various properties and behavior of functions, variables, types, etc.
If a non-GCC-compatible compiler tries to compile code that uses this extension, it won't able to do so and will throw a syntax error.
In order to avoid this, the author of the code makes the preprocessor replace this keyword with nothing if __GNUC__ is not defined (i. e. if the compiler is not a GCC-compatible one), so that the code builds on a bigger variety of platforms.