2009-04-02 1 views
2

В программном проекте (некоторый старый компилятор C) у нас есть много переменных, которые должны быть сохранены нормальными и инвертированными.Макро вопросы

Есть ли у кого-нибудь идея, как я могу сделать такой макрос?

SET(SomeVariable, 137); 

, который будет выполнять

SomeVariable = 137; 
SomeVariable_inverse = ~137; 

Edit:

Самое лучшее решение, кажется:

#define SET(var,value) do { var = (value); var##_inverse = ~(value); } while(0) 

Спасибо за ответы

+0

Если вы хотите указать, что это лучшее решение, вы должны выбрать его как «принятое» решение; который дает бонус репутации пользователю, который внес свой вклад, и отмечает его как решение, которое решило вашу проблему. –

+0

Должен ли макрос также иметь возможность гарантировать, что var = ~ var_inverse сразу перед выполнением задания? do {assert (var == ~ var ## _ inverse); var = (значение); var ## _ inverse = ~ (value); } while (0). Если вы используете этот макрос везде, это ваш лучший шанс проверить. –

ответ

5

Одна из опасностей, о которых я не упоминал, заключается в том, что аргумент макроса «значение» оценивается дважды в большинстве решений. Это может вызвать проблемы, если кто-то пытается что-то вроде этого:

int x = 10; 
SET(myVariable, x++); 

После этого вызова, MYVARIABLE бы 10 и myVariable_inverse будет ~ 11. К сожалению. Незначительные изменения в решение JaredPar в решает эту проблему:

#define SET(var,value) do { var = (value); var##_inverse = ~(var); } while(0) 
11

Попробуйте это

#define SET(var,value) do { var = (value); var##_inverse = ~(value); } while(0) 

EDIT

Пара ссылок на причину добавления делать/в то время как в макро

+0

Есть ли где-нибудь статья, объясняющая, почему вы используете макроконструирование из цикла do? Мне любопытно, почему ... –

+0

Вкратце: обертка do..while позволяет макросу в целом вести себя как утверждение, что хорошо. Думайте, если/else, фигурные скобки и прочее. – unwind

+0

Общая идея заключается в том, что вы хотите, чтобы макрос работал как вызов функции, что означает, что вы можете писать такие вещи, как «SET (a, 1)»; или "if (foo) SET (a, 1); else SET (a, 2);". Подробнее см. Http://c-faq.com/cpp/multistmt.html. –

1
#define SetInverse(token, value) { token = value; token##_inverse = ~value; } 

сглазить, Джаред - как время (0) в ваш

+0

Это становится немного глупым при использовании с обычной точкой с запятой SetInverse (a, 48); завершает создание нулевого оператора в коде, который (для меня) намного уродливее, чем цикл do..while (0). – unwind

+0

Я задавался вопросом, может ли стринирование быть полезным, но я никогда не использовал его в гневе, и я не мог понять, как его можно использовать здесь. Документы говорят, что ## предотвращает замену идентификатора - действительно ли это работает посреди сплошной строки? – 2009-04-02 13:58:14

+0

Увы, 'do {} while (0)' необходимо: это не удается, если оно записано как 'if (1) SetInverse (t, 0); else {printf ("unmatched 'else'! \ n");} ' – ephemient

4

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

+0

Это мешает безопасности. Каждая важная переменная должна храниться как обычная, так и инверсная. Каждую секунду переменные проверяются. Если они ошибаются, адские промахи теряются. – nuriaion

+0

Может иметь смысл в среде с сильным ядерным излучением. Но я QUITE боюсь, что разработчик встроенного ПО в такой среде должен задать здесь такой вопрос. – MSalters

+0

В разработке встроенных ПО есть новички. – mouviciel

4

Вы можете сделать это в одном заявлении, которое избавляет от необходимости использовать do {} while (0).

#define SetInverse(token, value) (token##_inverse = ~(token = (value))) 

Кроме того, это только один раз (value) расценивается, что всегда приятно.

+0

>> Кроме того, это только evalutes (значение) один раз, что всегда приятно << - определенно, целесообразная причина использовать этот метод. –

+0

Небольшая модификация делает этот макрос возвратом значения (значения), точно так же, как если бы оно было назначением (как раз по случайности оно используется в самом большом выражении, которое действительно, если, вероятно, необычно): #define SetInverse (токен , value) (token = ~ (токен ## _ inverse = ~ (значение))) –

+0

Мне было предложено добавить '(void)' cast в определение, чтобы убедиться, что он не может использоваться в более крупном выражении, но да, чтобы оценить значение 'значение' довольно легко. – ephemient

0

Просто предложить альтернативный метод:

магазина каждой переменной в качестве структуры, как это:

typedef struct 
{ 
    u32 u32Normal; 
    u32 u32Inverted; 
} SafeU32TYPE 

Тогда есть функция, которая принимает указатель на один из них, наряду со значением быть множество, и магазины, которые дорожат своим обратным:

void Set(SafeU32TYPE *pSafeU32, u32Data) 
{ 
    if(pSafeU32 != NULL) 
    { 
     pSafeU32->u32Normal = u32Data; 
     pSageU32->u32Inverted = ~u32Data; 
    } /* if */ 
} /* Set() */ 

Advantage: если вам нужна функция набора сделать SOMET hing более мощный, например, проверка границ или хранение более сложным способом, тогда его можно легко расширить.

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