Modern C, Second Edition


A new edition of the book Modern C is now available under a CC license via the following page

https://modernc.gforge.inria.fr/

 This edition is the result of a collaboration with Manning, and improves a lot over the previous edition; material has been rewritten and reordered, a lot of graphics have been added. Manning is in the process of producing nicely formatted print and eBook versions of this, you may also find links and information how to purchase this through the central link above.

 

C2x

The C committee (AKA WG14) has now moved to construct the next real revision of the C standard. This is commonly referred to “C2x”, where the “x” is supposed to represent the digit of the year in which this new standard will appear. The whole procedure is ruled by the C2x Charter that describes and fixes what kind of additions and improvements we want to see in C2x.

We regularly publish working drafts that includes the changes that have been added so far. Other than for the C17 process, that was a pure bug fix release, such working papers introduce normative changes and are public and so I will keep up links to the ones that I find relevant, here. The first of these  is still mostly C17, with only a few additions:

The most recent ones can be found here:

We keep a list of changes and their status here

For discussion of all of these changes and other possible features that you like (or don’t) to be included in C2x, please refer to the appropriate channels. The best is to get involved in the standard’s process by adhering to your national standards body, come to the WG14 meetings and/or subscribing to the committee’s mailing list. Please have in mind that all contributions should be constructive, we aren’t fans of abusive language, insults or denigration.

Comments for this page are switched off. If you have spotted errors or omissions, please contact me directly via mail. Plain mail, please, no twitter or alike, this is your Turing test.


Possible future additions to the C standard

There are many other ideas and documents floating around for inclusion into C2x. The following list is certainly not complete and biased by my personal preferences:

    • Ease the definition of extended integer types, see N2303
    • Add wide or bignum integer types
    • Add type generic interfaces for string functions to the C library, see N2068
    • Add general constants for all data types
    • Extend the concept of integer constant expressions (ICE)
    • Remove ATOMIC_VAR_INIT, see n2390 
    • Revise atomics, see n2389 
    • Revise threads, see n2391 
    • Revise the memory model, see N2294
    • Remove K&R function declarations and definitions
    • Remove one’s complement and sign-magnitude representations of signed integers, see N2218
    • Remove the * form of VLA function parameter declarations
    • Improve array bound propagation and checks
    • Add a new calling conventions with error return for library functions that avoids the use of errno
    • New string representations for NaNs, see N2290
    • Extend specifications for enum types, see N2008
    • Remove or deprecate Annex K, see N1969
    • Add a type aware print utility with format specification syntax similar to python
    • Add multibyte/wide string conversion functions, see N2282
    • char8_t: A type for UTF-8 characters and strings, see N2231
    • Adding the u8 character prefix, see N2198
    • Harmonizing left-shift behavior with C++, see N2161
    • __has_include for C, see N2101
    • add more TIME_ variants to timespec_get, integrate POSIX time conversion functions, see N2402
    • Add wchar_t and FILE to all headers that use them
    • Revise spelling of keywords and make them feature tests, see N2392
    • Make false and true first-class language features, see N2393
    • Add a simple specification of nullptr, similar to C++, see N2394
    • upgrade C library headers with [static 1]
    • type deduction from initializer, similar as C++’s auto
    • constexpr to evaluate expressions at compile time as in C++
    • __VA_ARGS__ comma omission and comma deletion, see N2160
    • TS 18661-3 as annex, see N2342
    • Improved Rules for Tag Compatibility, see N2366
    • Remove support for storage-class specifiers not in first position
    • Remove support for tentative definitions
    • Inline variables
    • Initializers for selection statement
    • Allow to not name parameters in function definitions

Spurious failures of thread functions

C11’s thread interface was not very clear on failure conditions that some functions might encounter. It was not clear that wait functions for conditional variables (cnd_t) and tentative locking of mutexes (mtx_t) may fail spuriously, that is with not apparent reason for the caller. By lack of such a specification, it was not clear how C11 threads could be realized by POSIX threads, e.g.

Allowing spurious wakeups is particularly important for the wait functions, because it makes implementing the cnd_t type much easier, in particular for the special case that the caller of cnd_signal or cnd_broadcast does not hold the lock on the corresponding mutex. On the other hand, from an application point of view this does not change much. Even without spurious wakeups, a thread that called `cnd_wait`, e.g, must in any case check the real condition they are interested in.

Continue reading “Spurious failures of thread functions”

compare exchange compares memory and not value

In C11, 7.17.7.4, introduces atomic_compare_exchange generic functions. These are precious tools when using atomics: they allow to conditionally store new data in an atomic variable and to retrieve a previous value of it, eventually. You can see that as a generalization of atomic_fetch_and_add where we are also able to retrieve a counter value and change it at the same time.

C11 stated that the value would be taken into account for the conditional part, that is that the existing value would be compared to a desired value. This works well for arithmetic types, where value and object representation are mostly the same. It works less well if the atomic type is a structure because struct types simply have no equality operator.

Continue reading “compare exchange compares memory and not value”

C17: reformulations for atomic_flag

In C11, there was a problem with the fact that atomic_flag is one of the rare types that is not considered to have a value, but it only has state (clear and set) which is changed via function calls. (mtx_t and cnd_t are other examples of such types.) There was no established relation between these states and the return value of the atomic_flag_test_and_set functions (which is bool).

C17 clears that up by prescribing the return values of atomic_flag_test_and_set

Continue reading “C17: reformulations for atomic_flag”

C17: rvalues and function types drop qualifiers

At least since C99 the C standard has:

The properties associated with qualified types are meaningful only for expressions that are lvalues.

This phrase expresses the intent that type qualifiers are to be ignored in “some sense” if they appear in other contexts, namely for the values of expressions, i.e. rvalues.

Until the invention of _Generic in C11, nobody really cared what happened to qualifiers of expressions: only the value and size, not the type itself of an expression was observable from inside a C program.

This changed with C11, _Generic makes types observable. Unfortunately the formulation of the _Generic feature itself did not make it clear if it could be used to also detect the qualifications. C11 leaves the following questions unresolved

    1. Are there contexts where qualified rvalues can pop up?
    2. Can _Generic distinguish a qualified argument from an unqualified one?

In particular the lack of clarification of the second question lead to divergence in the implementation of the _Generic feature in mainline compilers.

In our work for C17, we tackled these questions in two “defect reports”, DR 423 (for a.) and DR 481 (for b.).

DR 423

For the first, there are two context that seemed to allow values of expressions to have qualifiers: casts and function returns. For both it was decided that the intent of the standard never had been to have qualifications here, and that the standard should be fixed to clearly state that intent. Therefore DR 423 proposes two modifications. For casts, it changes the first phrase of 6.5.4.p5 (change in red)

Preceding an expression by a parenthesized type name converts the value of the expression to the unqualified version of the named type.

For function returns, the situation is a bit more complicated, because the current syntax allows return types of functions to be qualified. E.g.

double const foo(void) {
    return 0;
}

Is a valid definition of a function. Whenever it is called, the return value is an rvalue, so is this value a double or a double const?

The answer that was found is to treat the above function as if the const where not present. That is, the return type of the function is adjusted to the unqualified type. The proposed change for 6.7.6.3 p5 is

If, in the declaration “T D1“, D1 has the form
D ( parameter-type-list )
or
D ( identifier-list opt )
and the type specified for ident in the declaration “T D” is “derived-declarator-type-list T“, then the type specified for ident is “derived-declarator-type-list function returning the unqualified version of T“.

Beware that this has more effects than just changing the qualification of value expressions. Compilers that will claim to be compliant to C17 must accept the following:

double (*foop)(void) = foo;
double const (*foopc)(void) = foop;

That is any function type or type derived from that behaves as if the qualifier were not present. Most current compilers will probably see these as a constraint violations. Also, since now types that may have been considered different are now clearly specified to be the same, the following expression is a constraint violation:

_Generic(X,
    double (*)(void): 1,
    double const (*)(void): 2
)

because a generic expression is not supposed to have two entries with compatible types. Most current compilers probably would accept that construct, so they’d have to be fixed.

DR 481

For _Generic it was decided that the intent of the construct was to implement some kind of function overloading for C and that it was meant to have a behavior that is the closest possible to that intended feature. So it was decided to force that the type of a controlling expression is seen as if it would undergo the same conversions as arguments to function calls. The proposed text for 6.5.1.1 reads

The type of the controlling expression is the type of the expression as if it had undergone an lvalue conversionnew), array to pointer conversion, or function to pointer conversion. That type shall be compatible with at most one of the types named in the generic association list.

new) lvalue conversion drops type qualifiers.

 

As a consequence the following code is still valid

_Generic(X,
    double: 1,
    double const: 2
)

only that the second association can never trigger. Therefore it would be reasonable for compilers to give a warning diagnostic for such a generic expression.

This does not mean, though, that qualifiers are not observable at all. You just have to put a little bit more effort into it:

_Generic(&X,
    double*: 1,
    double const*: 2
)

This should still work and both associations may trigger depending on whether or not you pass an lvalue that is const qualified or not.