c++externrestrict-qualifier

Include C99 code using the restrict keyword in C++ source


We use extern "C" { ... } to include C header files in C++. This does not seem to work if the C file uses C99 keywords such as restrict. For example:

test.h

#ifndef TEST_H
#define TEST_H

extern void test(int * restrict x, const int * restrict y);

#endif

test.c

#include "test.h"

int main(void)
{
    int n = 1;
    int m = 2;
    test(&n, &m);
    return 0;
}

test.cpp

extern "C" {
#include "test.h"
}

int main(void)
{
    int n = 1;
    int m = 2;
    test(&n, &m);
    return 0;
}

If we run gcc -Wall -Wextra -Wpedantic test.c -c or clang -Weverything test.c -c, the compilation is done silently without errors or warnings. However g++ test.cpp -c results in a error. Similarly, clang++ test.cpp -c fails.

Question: Is there a portable way to use C99 (or higher) keywords in a header file, and then include that header file for use in C++? Various C libraries make use of the restrict keyword, and it would seem desirable to want to be able to use them in a C++ library. As a simple example, the C version of memcpy (I know the C++ version of memcpy does not use restrict, of course, but this is a simple enough example): https://en.cppreference.com/w/c/string/byte/memcpy

Please note: Non-portable solutions exists. Such as:

#if defined(__GNUC__) || defined(__clang__)
// GCC or clang
#define restrict __restrict__
#else
// MSVC
#define restrict __restrict
#endif

or something similar. I am seeking portable, standards-compliant solutions.


Solution

  • First, restrict on a parameter has no effect in a function declaration that is not a definition. Qualifiers only apply to lvalues, and calls to a function pass arguments as plain values. Only in the function definition are the parameters objects that can have qualifiers. C 2024 6.7.7.4 says:

    … In the determination of type compatibility and of a composite type,… each parameter declared with qualified type is taken as having the unqualified version of its declared type…

    So, if you want to include a header (declarations only, no function definitions) in a C++ file, you can simply suppress the restrict keyword, as with:

    #if __cplusplus
        #define restrict
    #endif
    

    (restrict could have an effect in a function declaration if it is inside a parameter rather than directly on the parameter, as in void foo(int * restrict *p);. I do not believe I have ever seen that used in code. If it were present in that way, it would make the C++ altered function declaration incompatible with the C definition.)

    Second, even in a function definition, the only purpose of restrict is to promote optimization. Removing restrict from a correct program keeps a correct program, with the _Generic exception noted below. C 2024 6.7.4.1 says:

    … The intended use of the restrict qualifier (like the register storage class) is to promote optimization, and deleting all instances of the qualifier from all preprocessing translation units composing a conforming program does not change its meaning (i.e. observable behavior), unless _Generic is used to distinguish whether or not a type has that qualifier…

    I have cited C 2024, but this is the same from C 1999 on, except there was no _Generic in C 1999.