C11 Generic: как работать со строковыми литералами?
Используя функцию _Generic
в C11, как вы справляетесь со строковыми литералами?
Например:
#include <stdio.h>
#define foo(x) _Generic((x), char *: puts(x))
int main()
{
foo("Hello, world!");
return 0;
}
Выдает эту ошибку на clang:
controlling expression type 'char [14]' not compatible with any generic association type
Замена char *
на char[]
дает мне
error: type 'char []' in generic association incomplete
Единственные способы (насколько мне известно) получить это для компиляции:
- приведите строковый литерал к соответствующему типу. Это некрасиво и (на мой взгляд) поражает точку зрения
_Generic
в первую очередь. - используйте
char[14]
в качестве спецификатора типа. У тебя есть получил , чтобы шутить надо мной...
_Generic
, но, очевидно, нет. Итак, как я использую _Generic
со строковыми литералами? Это единственные два варианта?
Я использую clang 3.2 в Debian. К сожалению, это единственный компилятор, к которому у меня есть доступ, который поддерживает эту функцию, поэтому я не могу сказать, является ли это ошибкой компилятора или нет.
2 ответа:
Вот решение:
#include <stdio.h> #define foo(x) _Generic((0,x), char*: puts(x)) int main() { foo("Hello, world!"); return 0; }
Это компилирует и производит:
$ clang t.c && ./a.out Hello, world!
Это несколько хромает, но я не нашел лучшего способа заставить
x
распадаться на указатель на char или соответствовать его типу в нечеткой форме, которую вы требуете, с Apple LLVM версии 4.2 (clang-425.0.28) (на основе LLVM 3.2 svn).Согласно этой записи в блоге Йенса Густеда , поведение GCC отличается (в GCC строки автоматически распадаются на указатель в контексте
_Generic
, по-видимому).Кстати, в языке Си тип строкового литерала-массив
char
, а неconst char
. Отклонениеchar []
как type-name в generic-association не является ошибкой компилятора:Универсальная выборка должна иметь не более одной стандартной универсальной ассоциации. Имя типа в универсальной ассоциации должно указывать полный тип объекта , отличный от изменяемого типа. (6.5.1.1:2 с моим акцентом)
Я нашел способ избежать использования хитрого трюка
(0,x)
.Если вы используете строковый литерал , то тип
char[s]
, гдеs
- размер строкового литерала.Как вы получаете такой размер?, использовать оператор
sizeof
:Я попытался скомпилировать его с помощью clang и Pelles, и это сработало.#include <stdio.h> #define Test( x ) _Generic( ( x ) , char*: puts , \ const char*: puts , \ const char[sizeof( x )]: puts , \ char[sizeof( x )]: puts )( x ) int main(void) { char str[] = "This" ; Test( str ) ; Test( "works" ) ; char str2[10] = "!!!" ; Test( str2 ) ; return 0; }
Единственная проблема, которую вы все еще должны разыгрывать массивы переменной длины.
Попробовав еще немного, я нашел другой аналоговый способ делать то, что Паскаль Куок сделал, использовал
&*
операторы:#include <stdio.h> #define foo(x) _Generic( ( &*(x) ), char*: puts , const char*: puts )( x ) int main() { foo("Hello, world!"); return 0; }