2016-10-20 2 views
4

Для того, чтобы какой-то код компилировать в C и C++ Я использую это в нескольких местах:Возможно ли реализовать тип GNU C (x) с помощью C11's _Generic?

#ifdef __cplusplus 
    #define typeof(x) decltype(x) // works ok in most cases, except C++ reference types 
#endif 

char* a = (typeof(a)) malloc(4); 

В C, это компилирует char* a = (char *) malloc(4) где литая является абсолютно ненужным, но в C++ void * не неявно назначен char * и ошибка выдается, если литой нет.

Это так же хорошо, когда я могу скомпилировать с -std=gnu11 на GCC или Clang, но что, когда я хочу, чтобы мой код был скомпилирован как ISO C11? Я думал, что я мог бы использовать _Generic C11 для реализации typeof(x) бросить несколько типов:

#define gettype(x) _Generic((x), \ 
    short:  (short), \ 
    char:  (char ), \ 
    char*:  (char *), \ 
    default:  (void *) ) 

int main (void) { 
    short a = (gettype(a)) 1; 

    return a; 
} 

Но независимо от того, какой тип определен в gettype(x) дается в декларации a «s,

typeof.h: In function ‘main’: 
typeof.h:2:24: error: expected expression before ‘,’ token 
    short:  (short), \ 
         ^
typeof.h:8:13: note: in expansion of macro ‘gettype’ 
    char a = (gettype(a)) 1; 
      ^~~~~~~ 
typeof.h:8:25: error: expected ‘,’ or ‘;’ before numeric constant 
    char a = (gettype(a)) 1; 

gcc -E говорит, что линия расширяется просто отлично:

short a = (_Generic((a), short: (short), char: (char), char*: (char *), default: (void *))) 1;       ^

Есть ли какой-то синтаксис, который у меня отсутствует, или я s это просто невозможно в C для генерации кода с использованием _Generic?

+2

Хотя '_Generic' вряд ли можно использовать вне макроса, он не может быть частью препроцессора. Таким образом, он не может обеспечить замену текста. – Olaf

+0

Было бы лучше обеспечить полную совместимость с C и совместимость с C++, чем отсутствие совместимости с C и C++. – user694733

+0

@ user694733 спасибо за вашу критику, но я уверен, что этот код будет только скомпилирован как C с GCC или Clang - совместимость с C++ для MSVC, которая едва поддерживает C90. – cat

ответ

2

Проблема заключается в том, что вы не можете иметь частичное выражение внутри родового выбора. Возможным обходом может стать полное выражение внутри него:

#define cast(from, to) _Generic((from), \ 
    short:  (short) (to),   \ 
    char:  (char) (to),   \ 
    char*:  (char*) (to),   \ 
    default:  (void*) (to)) 

int main (void) { 
    short a = cast(a, 1); 

    return 0; 
} 
3

Нет, это невозможно. (Теперь смотрите кто-то доказать, что я не прав!)

В выражении _Generic каждый родовое-ассоциация либо

имя-типа: назначение выражение

или

default: присвоение-выражение

Это не может быть имя типа или что-то, что расширяется до имени типа. В частности, хотя выражение _Generic разрешено во время компиляции, это не макрос. Конечным результатом всегда является выражение.

И я не верю, что есть какой-либо другой способ сделать то, что вы хотите в стандартной C.

+0

Это, как я боялся! Ах, хорошо, вот что я получаю за то, что думаю, что впереди 1979 года :) – cat

+0

@cat 1979 не имеет к этому никакого отношения. Никакой язык, старый или новый, не позволяет частичные выражения. Это не работает по той же причине, что и 'int x =;' не работает - это не полное выражение. – Lundin

+0

@ Lundin Я в основном использую гомокиноязычные языки (например, LISP) для «реальных» приложений, поэтому меня всегда шокирует то, что на C-подобных языках синтаксические элементы, которые чувствуют себя так же, как и другие выражения, не являются. – cat

Смежные вопросы