2015-03-22 3 views
1

Макросы подкачки, которые берут тип, довольно хорошо известны.Portable C SWAP-макрос, который не требует аргумента 'type' и не использует memcpy.

#define SWAP(type, a_, b_) do {  \ 
    type SWAP, *a = &(a_), *b = &(b_); \ 
    SWAP = *a;       \ 
    *a = *b;       \ 
    *b = SWAP;       \ 
} while (0) 

также: Macro SWAP(t,x,y) exchanging two arguments of type t

Можно ли реализовать эту функциональность в то же время ...

  • не портативный (не компилятор конкретных typeof)
  • без использования вызовов функций, таких как memcpy
    (что не гарантировано для оптимизации, it не было в моих тестах, по крайней мере)

Я придумал недостатки метод, который использует-структуру, определенную как размер входных данных.

#define SWAP(a_, b_) do \ 
{ \ 
    struct { \ 
     char dummy_data[sizeof(a_)]; \ 
    } SWAP, *a = (void *)(&(a_)), *b = (void *)(&(b_)); \ 
    /* ensure sizes match */ \ 
    { char t[(sizeof(a_) == sizeof(*a)) ? 1 : -1]; (void)t; } \ 
    /* check types are compatible */ \ 
    (void)(0 ? (&(a_) == &(b_)) : 0); \ 
    SWAP = *a; \ 
    *a = *b; \ 
    *b = SWAP; \ 
} while (0) 

... но она может потерпеть неудачу, если временный struct получает проложенный компилятором (в зависимости от ССЗ __packed__ не будет работать, но тогда его больше не портативный)
Он также может иметь проблемы с выравниванием в зависимости от архитектуры
.

+4

Интересный вопрос, но почему? – tangrs

+2

Почему нет 'memcpy()' но назначение в порядке? – pmg

+2

Ваш подход также вызывает неопределенное поведение из-за нарушения псевдонимов. – Sneftel

ответ

1

Мне любопытно узнать, при каких обстоятельствах такая структура будет заполнена, и будет ли такое дополнение соответствовать.

Вы можете добавить статическую проверку для sizeof(SWAP) == sizeof(a_) и использовать memcpy, если тест не выполнен (заполнение было вставлено в конце структуры SWAP).

Также не используйте простые имена, такие как a и b в теле макроса, поскольку они могут быть расширены макросами, если пользователь определил эти идентификаторы как макросы. Использование a и b в качестве аргументов макроса не представляет проблемы.

#define SWAP(a, b) do {        \ 
    struct {          \ 
     char a_[sizeof(a)];       \ 
    } SWAP, *a_ = (void *)&(a), *b_ = (void *)&(b); \ 
     if (sizeof(SWAP) == sizeof(a)) {   \ 
      SWAP = *a_; *a_ = *b_; *b_ = SWAP;  \ 
     } else if (a_ != b_) {      \ 
      memcpy(&SWAP, a_, sizeof(a));   \ 
      memcpy(a_, b_, sizeof(a));    \ 
      memcpy(b_, &SWAP, sizeof(a));   \ 
     }           \ 
    } while (0) 

Вы можете добавить чек на sizeof(a) == sizeof(b) как плохую попытку укомплектовывает к типу проверки этого макроса перегружен.

+0

В моем текущем макросе я проверяю тип, просто удалив из примера, чтобы сделать его короче. – ideasman42

+0

Согласно @Jens Gustedt, структура никогда не будет дополнена. Заинтересованность найти, не отличается ли это от C spec - http://stackoverflow.com/questions/29195926 – ideasman42

+0

Этот код завершается с ошибкой, если 'a' и' b' являются одним и тем же объектом (поскольку источник и место назначения 'memcpy' перекрываются). –