2016-01-12 2 views
3

Можно ли определить макрос для препроцессора C, который принимает массив в качестве аргумента и расширяется до <type of array elements>_string? Например, если x в массиве целых чисел, макрос, вызываемый с аргументом x, должен быть расширен до int_string.Использование оператора вставки `##` с типами в C

Я попытался с

#define TypePaste(array) typeof(array[0])##_string 

, но она расширяется до )_string.

Даже с использованием нескольких уровней косвенности для операнда ## макрос не разворачивается правильно.

+3

Представьте предпроцессорные директивы как немой механизм, который получает свою очередь перед компиляцией, для строковых манипуляций, где строки являются строками вашего кода. –

+0

Существуют способы, но это зависит от того, хотите ли вы, чтобы макрос создавал новый тип, новое имя переменной или ссылался на существующий тип или переменную. – Lundin

+1

Звучит немного как проблема xy. Чего вы пытаетесь достичь? –

ответ

3

Это не все, что ясно, что проблема, которую вы пытаетесь решить, но, учитывая Ваш комментарий:

макрос должен расширяться имя существующей функции. Я хотел бы определить функцию <type>_string для каждого существующего типа, а затем использовать макрос, чтобы выбрать нужную функцию в соответствии с типом заданного массива.

Тогда вы могли бы использовать C11 _Generic ключевое слово:

#include <stdio.h> 

void int_string (size_t size, int array[size]) 
{ 
    printf("I am %s, do stuff here.\n", __func__); 
} 

void float_string (size_t size, float array[size]) 
{ 
    printf("I am %s, do stuff here.\n", __func__); 
} 

#define TypePaste(array)   \ 
    _Generic(array,    \ 
      int: int_string, \ 
      float: float_string) \ 
    (sizeof(array)/sizeof(*array), array) // function parameters 



int main() 
{ 
    int i_arr[5]; 
    float f_arr[3]; 

    TypePaste(i_arr); 
    TypePaste(f_arr); 
} 

Выход:

I am int_string, do stuff here. 
I am float_string, do stuff here. 

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

6

Это невозможно. На этапе -перехода (фаза предварительной обработки), где макросы расширены и маркеры объединены, компилятор (на данный момент, препроцессор) еще не имеет понятия типа и, следовательно, не может генерировать типы.

+2

Предварительная обработка является одной из нескольких фаз нумерованного перевода, в частности фазы 4 (C11 § 5.1.1.2). – Potatoswatter

+0

Итак, нет способа заставить компилятор сначала оценить 'typeof()' или каким-то образом вставить строки после того, как 'typeof()' был расширен? –

+3

@ OscarCharles Нет, нет. Если вы хотите сделать что-то подобное, вам нужно написать собственный генератор кода. Если вы спросите проблему, которую вы пытаетесь решить, сделав это, возможно, мы сможем найти другое решение. – fuz

0

C11's _Generic Выбор типа - это «правильный» способ сделать то, что вы хотите. Существуют и другие, зависящие от платформы решения, жесткие.

Если вы используете GCC – вы не говорите так eplicitly, но вы используете расширение GCC в typeof уже – вы можете использовать ССЗ statement expresions и nested functions создать функцию сравнения для qsort на месте:

double a[5] = {8.4, 8.1, 9.3, 12.2, 5.2}; 

qsort(a, 5, sizeof(*a), ({ 
    int cmp(const void *p, const void *q) { 
     const typeof(a[0]) *pp = p; 
     const typeof(a[0]) *qq = q; 

     return (*pp < *qq) ? -1 : (*pp > *qq); 
    } 
    cmp; 
})); 

Это создает функцию и возвращает ее адрес. (Последним выражением составного выражения является его значение. Область локальных переменных - выражение оператора, но вложенная функция не создается в стеке, поэтому ее безопасно возвращать указатель на эту функцию.)

Для примитивных типов, где вы хотите, чтобы отсортировать по операторам сравнения < и >, вы можете превратить это в макросе:

#define COMPARE(ARRAY)({    \ 
     int cmp(const void *p, const void *q) {   \ 
      const typeof(ARRAY[0]) *pp = p;    \ 
      const typeof(ARRAY[0]) *qq = q;    \ 
      return (*pp < *qq) ? -1 : (*pp > *qq);  \ 
     }            \ 
     cmp;           \ 
    }) 

qsort(a, 5, sizeof(*a), COMPARE(a)); 

или даже:

#define SORT(ARRAY, N)         \ 
    qsort(ARRAY, N, sizeof(*ARRAY), COMPARE(ARRAY)) 

SORT(a, 5); 

Это не Стандарт C, поэтому, если вам нужна совместимость между платформами, это не может быть и речи.

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