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

Discussion in 'C++' started by mathog, Oct 17, 2013.

  1. mathog

    mathog Guest

    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
    mathog, Oct 17, 2013
    #1
    1. Advertising

  2. mathog

    Öö Tiib Guest

    On Thursday, 17 October 2013 20:09:54 UTC+3, mathog wrote:
    > 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
    Öö Tiib, Oct 17, 2013
    #2
    1. Advertising

  3. On 17.10.2013 19:09, mathog wrote:
    > 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
    Alf P. Steinbach, Oct 17, 2013
    #3
  4. mathog

    mathog Guest

    Alf P. Steinbach wrote:
    >
    > 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
    mathog, Oct 17, 2013
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Victor Bazarov

    #include "file" -vs- #include <file>

    Victor Bazarov, Mar 5, 2005, in forum: C++
    Replies:
    4
    Views:
    523
    Exits Funnel
    Mar 6, 2005
  2. PTM
    Replies:
    1
    Views:
    317
    Andy Dingley
    Nov 12, 2007
  3. naveeddil
    Replies:
    0
    Views:
    550
    naveeddil
    Jan 4, 2008
  4. Andreas Bogenberger
    Replies:
    3
    Views:
    881
    Andreas Bogenberger
    Feb 22, 2008
  5. Mark
    Replies:
    2
    Views:
    385
Loading...

Share This Page