2012-01-17 6 views
5

Рассмотрим следующую функцию C99:Есть ли фиктивная lvalue, которая может использоваться, когда ничего не должно быть выполнено?

void port_pin_set(const bool value, const uint8_t pin_mask) 
{ 
    if (value) { 
     PORT |= pin_mask; 
    } else { 
     PORT &= ~pin_mask; 
    } 
} 

С PORT будучи define, например:

#define PORT (P1OUT) 

Есть ли способ, чтобы переопределить PORT так, что:

  • принято как lvalue,
  • функция не делает anythin г.

Что я хочу сделать, так это сохранить источник функции как есть, при компиляции его ничего не делать.

Редактировать: Я знаю, что использование такого lvalue может быть не лучшим решением. Я не ищу лучшего решения этой конкретной проблемы, меня интересует сам язык. Это теоретический вопрос, а не прагматичный.

+0

Я думаю, что настоящий вопрос вот почему вы хотите это сделать? В то время как интересный магический вопрос препроцессора C, я сомневаюсь, что вам действительно нужно это сделать. –

+0

Мне больше всего любопытно. Я бы удалил файл из команды компиляции, но функция имеет встроенное определение в заголовочном файле '# include'd в нескольких местах. – Gauthier

+0

Вы можете просто обработать тело функции –

ответ

10

C99 имеет сложные литералы, которые могут использоваться для выполнения такой задачи. Их синтаксис слепок с последующим инициализатором:

#define PORT ((int){0}) 

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

Любой достойный компилятор оптимизирует задания для такого составного литерала.

+0

Блестящий, это именно то, что я искал, у меня было ощущение, что это возможно. Вы заставили меня снова прочитать о сложных литералах, спасибо! – Gauthier

+0

Как указано в редактировании моего оригинального вопроса, я не буду реализовывать его (ifdefing вместо этого более читаем). Но мой вопрос был направлен на языковые конструкции, и этот ответ просто прибил его. – Gauthier

2

Это должно сделать это в C99:

#ifdef PORT 
#undef PORT 
#endif 

#define PORT int x = 0; x 

для вашего случая. Но я предлагаю вам поставить весь код между #ifdef-х вместо переопределение PORT:

void port_pin_set(const bool value, const uint8_t pin_mask) 
{ 
#ifdef BUILD_PORT_PIN_SET 
    if (value) { 
     PORT |= pin_mask; 
    } else { 
     PORT &= ~pin_mask; 
    } 
#endif 
} 
+4

Несомненно, это предотвратит использование «ПОРТА» в середине блока или несколько раз за блок, не говоря уже о возможности наличия пользовательской переменной «x». (Я предполагаю, что OP хочет иметь достаточно общее решение, а не одно, которое работает только для этого примера.) – NPE

+0

@aix Это было направлено на его конкретный пример. Это похоже на конкретность. –

+0

вы не можете объявить переменную в середине блока в C –

8

Вы можете определить переменную того же типа, как ваш P1OUT (скажем, unsigned char), сделать его доступным в заголовке, и определить его в одном из источников, как это:

заголовок:

extern unsigned char dummy_P1OUT; 
#define PORT (dummy_P1OUT) 

C файл:

unsigned char dummy_P1OUT; 

Usages:

PORT &= ~pin_mask; 

if (PORT & pin_mask) { 
    blink_led(); 
} 
+0

Не могли бы вы объяснить, как это решает проблему OP (заставляя компилятор не генерировать код.) – NPE

+3

@aix Я прочитал «компиляцию, чтобы ничего не делать», заставляя компилятор не генерировать код »: мое понимание намерения OP состоит в том, что он хочет, чтобы результат не менял вещи, относящиеся к его программе, подобно пересылке вывода программы в/dev/null в UNIX. – dasblinkenlight

+0

Достаточно честный. Я не знаю, что такое ОП, но эта интерпретация имеет смысл. – NPE

0

Есть извращения в C++, которые могут сделать трюк. Например, вы можете определить PORT, чтобы вернуть вам объект по значению, который реализует операторы и &=.

В C Я могу найти способ следующим образом: определить целочисленную переменную в начале, если функция, то PORT может быть определена либо этой переменной, либо соответствующей (P1OUT в вашем случае).

Когда PORT определяется локальной переменной - вы можете надеяться, что компилятор не примет этот код: присвоение локальной переменной значения, которое не используется.

0

Я тестировал заявление ниже на ubuntu, и он не записывает первый символ переменной окружения PATH, где он работает в Windows. Однако по определению он вызывает неопределенное поведение.

#define PORT (*(uint8_t*)(getenv("PATH"))) 

Итак, чтобы сделать его безопасным можно определить фиктивное значение среды в другом месте в программе и продолжают устанавливать, что вместо этого.

#include <stdlib.h> 

#ifdef PORT 
#undef PORT 
#endif 

#define SETDUMMYPORT (putenv("dummyPORT=x")) 
#define PORT (*(uint8_t*)(getenv("dummyPORT"))) 

Где-то в программе установить фиктивную переменную окружения:

int main(int argc, char* argv[]) 
{ 
    SETDUMMYPORT; 
} 

Затем PORT может быть использован как у вас есть в вашем вопросе.

+1

Вау, используя 'getenv' для моделирования сложных литералов, никогда не видел этого. Это действительно по-разному думает :) К сожалению, ваше решение очень опасно. Страница 'man'' getenv' говорит: * Вызывающий должен позаботиться о том, чтобы не изменять эту строку, поскольку это изменило бы среду процесса. * –

+0

Правильно, я не говорю, что это безопасно, и я даже заявил это в моем первом абзаце. Однако этот механизм контролируется, но я должен сказать, что C, конечно, поддается такому обману. – Jack

+0

нет, современный C имеет механизм для создания временных lvalues, который идеально подходит для работы. Пожалуйста, см. Мой ответ. –

1

Не обязательно lvalue, но я надеюсь, что это послужит вашей цели. Попробуйте

#define PORT if (0) P1OUT 

Он должен эффективно аннулировать полный отчет. Вы можете получить некоторые предупреждения, но это должно быть преодолимым ИМХО.

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

  • Нет связанных вопросов^_^