Testing C include file for C++ compatibility without a C++ caller?

M

mathog

I have a C package that until recently was callable by C++ programs
without generating warnings. Everything is properly wrapped up in

#ifdef __cplusplus
extern "C" {
#endif

which I always assumed precluded the possibility of a cleanly compiling
C module throwing warnings and errors when compiled by a C++ compiler.
However, recent versions of g++ throw warnings like this when some C++
modules include AND use one of the include files in the package:

.../../src/extension/internal/metafile-print.cpp:132:13: warning:
narrowing conversion of ‘((color >> 16) & 255u)’ from ‘uint32_t
{aka unsigned int}’ to ‘uint8_t {aka unsigned char}’ inside { } is
ill-formed in C++11 [-Wnarrowing]

These trace back to this line in the include file:

#define U_RGBA(r,g,b,a) (U_COLORREF){r,g,b,a}

which must be changed to this to eliminate the warning:

#define U_RGBA(r,g,b,a)
(U_COLORREF){(uint8_t)(r), (uint8_t)(g), (uint8_t)(b), (uint8_t)(a)}

Where U_COLORREF is defined earlier in that include file as:

typedef struct {
uint8_t Red; //!< Red color (0-255)
uint8_t Green; //!< Green color (0-255)
uint8_t Blue; //!< Blue color (0-255)
uint8_t Reserved; //!< Not used
} U_COLORREF, *PU_COLORREF;

The problem is that so far the warning only shows up when the U_RGBA is
actually USED in a C++ module, apparently with a 4 byte unsigned
(holding a value in the range 0-255) employed as one of the color values.

I have the c++ compiler line that when applied to the cpp file generates
the error message, but when run exactly the same way, but just on the
include file, like:

g++ .... -c include.h

there are no warnings.

Is it possible to test for this sort of issue using just the C++
compiler and the include file? (Using gcc or g++).

Thank you,

David Mathog
 
Ö

Öö Tiib

I have the c++ compiler line that when applied to the cpp file generates
the error message, but when run exactly the same way, but just on the
include file, like:

g++ .... -c include.h

there are no warnings.

Default behavior of that compiler with .h files is AFAIK to turn those
into precompiled headers (e.g. -x c++-header). If you want to preprocess
and compile .h file like c++ source file then use something like:

gcc -x c++ include.h
 
A

Alf P. Steinbach

I have a C package that until recently was callable by C++ programs
without generating warnings. Everything is properly wrapped up in

#ifdef __cplusplus
extern "C" {
#endif

which I always assumed precluded the possibility of a cleanly compiling
C module throwing warnings and errors when compiled by a C++ compiler.
However, recent versions of g++ throw warnings like this when some C++
modules include AND use one of the include files in the package:

../../src/extension/internal/metafile-print.cpp:132:13: warning:
narrowing conversion of ‘((color >> 16) & 255u)’ from ‘uint32_t
{aka unsigned int}’ to ‘uint8_t {aka unsigned char}’ inside { } is
ill-formed in C++11 [-Wnarrowing]

These trace back to this line in the include file:

#define U_RGBA(r,g,b,a) (U_COLORREF){r,g,b,a}

which must be changed to this to eliminate the warning:

#define U_RGBA(r,g,b,a)
(U_COLORREF){(uint8_t)(r), (uint8_t)(g), (uint8_t)(b), (uint8_t)(a)}

Where U_COLORREF is defined earlier in that include file as:

typedef struct {
uint8_t Red; //!< Red color (0-255)
uint8_t Green; //!< Green color (0-255)
uint8_t Blue; //!< Blue color (0-255)
uint8_t Reserved; //!< Not used
} U_COLORREF, *PU_COLORREF;

The problem is that so far the warning only shows up when the U_RGBA is
actually USED in a C++ module, apparently with a 4 byte unsigned
(holding a value in the range 0-255) employed as one of the color values.

The U_RGBA macro would not work for a standard-compliant C++03 compiler.

It uses a C99 feature for which there is a syntactically similar C++11
feature, which incidentally gives almost the same effect...

The expression

(U_COLORREF){ 1, 2, 3 }

is a C99 *compound literal*, as defined by C99 §6.5.2.5. Constraints on
the values are given by 7th para "All the semantic rules and constraints
for initializer lists in §6.7.8 are applicable to compound literals".
And when you go there you there you find in its 11th para that "The
initializer for a scalar shall be a single expression, optionally
enclosed in braces. The initial value of the object is that of the
expression (after conversion); the same type constraints and conversions
as for simple assignment apply", which means that any numeric conversion
is accepted -- in C99.

For C99 the parenthesis is part of the compound literal syntax and
cannot be omitted. In C++11 the parenthesis is ignored other than as a
logical grouping, yielding the expression

U_COLORREF{ 1, 2, 3 }

which syntactically, in C++11, is an *explicit type conversion* using
*functional notation*, as specified by C++11 §5.2.3. And in the 3rd
paragraph there you find that this specific form (which was introduced
in C++11, not available in C++03) is a **list initialization**. It
simply creates a temporary object with the given values or with those
values passed as constructor arguments, depending on the type.

In this case it's a list initialization of a C++ **aggregate** (because
U_COLORREF is an aggregate), and C++11 §8.5.1/2 then tells you -- as
did the g++ warning message -- that "If the initializer-clause is an
expression and a narrowing conversion (8.5.4) is required to convert the
expression, the program is ill-formed". That is, it's *ILL-FORMED*,
invalid, not correct, it shouldn't really compile but g++ is lenient.

So, the upshot is that you don't really want that thing.

It has different meanings in C and C++, won't compile with C++03
compiler, and shouldn't really compile with a C++11 compiler.

A general solution is to use a value factory function, and rely on
(common but not formally guaranteed) machine code inlining to avoid the
call overhead.

An alternative in this particular case is to use a 32-bit integer with
packing and unpacking macros, but it's not as type safe.

I have the c++ compiler line that when applied to the cpp file generates
the error message, but when run exactly the same way, but just on the
include file, like:

g++ .... -c include.h

there are no warnings.

The macro is not invoked.

Is it possible to test for this sort of issue using just the C++
compiler and the include file? (Using gcc or g++).

No, you need an invocation.

The invalid code for C++11 is the invocation, not the definition.


Cheers & hth.,

- Alf
 
M

mathog

Alf said:
The U_RGBA macro would not work for a standard-compliant C++03 compiler.
....

So, the upshot is that you don't really want that thing.

Interesting.

I will convert them to function calls which should eliminate the problem.

Thanks,

David Mathog
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top