2009-04-13 6 views
4

Я работаю над проектом на 8051, где подсчитывается каждый байт. Таким образом, я использую некоторые глобальные переменные, где я обычно этого не делал. Обычный способ передачи указателей в функцию добавляет сюда слишком много лишних накладных расходов.Как пометить код побочными эффектами?

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

bit global_error_flag = 0; 
bit global_data_ready_flag = 0; 

unsigned char A_Function (void) { 
    // Do some stuff 

    if (badness) { 
     global_error_flag = 0; 
     global_data_ready_flag = 1; 

     return 0; 
    } 

    if (data_is_ready_use) { 
     global_data_ready_flag = 1; 
    } 

    return a_value;  
} 

void Other_Function (void) { 
    unsigned char c; 

    c = A_Function(); 

    if(global_error_flag) { 
     // Do error stuff here. 
    } 
    else 
    if(global_data_ready_flag) { 
     // Do data processing here. 
    } 
    global_error_flag = 0; 
    global_data_ready_flag = 0; 

} 

Учитывая, что техника зла, есть ли способ сделать код более понятным?

Как лучше всего указать, какие вызовы функций будут иметь побочный эффект установки этих флагов? Есть комментарии достаточно? Должен ли я назвать функции, указывающие их API (квази-венгерский стиль)? Следует ли использовать макрос для отметки таких звонков:

#define FUNCTION_SETS_FLAGS(code) (code) 

FUNCTION_SETS_FLAGS(c = A_Function()); 

Другие идеи?

+0

Если вы используете 8-битный микроконтроллер с 256 байтами оперативной памяти (скажем). Тогда указатели на область данных также будут иметь ширину 8 бит. Я не понимаю причину использования глобальных переменных. Я могу понять, если он разделяется между ISR (Interrupt Service Routine) и основным циклом. Но ... – Alphaneo

+0

Большая проблема заключается в том, что параметры, выходящие за пределы первого, могут быть переданы в стек или путем присвоения им памяти (с моим конкретным компилятором). Если я скажу, что у меня есть 3 флага для 7 функций, то это потребляет от 21 байта дополнительной памяти. Большинство из которых мне нужно для буферизации ввода-вывода. Поэтому, если я могу уменьшить 12 байт до 7 бит, это чистая прибыль в 20 байт памяти. Что огромно в этом контексте. Параметр функции упаковки/распаковки также занимает больше места для кода. – daotoad

ответ

3

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

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

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

6

Используя соглашение, хотите ли вы назвать его «венгерским» или нет, это лучший способ, который я могу думать, чтобы отметить это безвыходным. Стилистически, какой-то префикс именования был бы предпочтительнее пустого #define, по крайней мере для меня.

Это на самом деле довольно распространено, я думаю. Я знаю, что среда программирования S60 использует множество обычных тегов для функций, чтобы указать, например, что они генерируют исключения.

2

Это на самом деле не поможет вам, но GCC имеет способ сделать противоположный того, что вы хотите: чтобы отметить функции, которые не имеют не побочных эффектов. См. Атрибуты const и pure. Это больше для оптимизации, чем документации, подумал: если компилятор знает, что данная функция не рассматривает какие-либо данные, кроме своих аргументов, она может выполнять более умные оптимизации, такие как loop-invariant code motion.

0

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

// Function func 
    // Does something 
    // Consumes ready_flag and sets error_flag on error. 

    int func() 
    { 
     if (ready_flag) 
     { 
      //do something then clear the flag 
      if (some_error) 
       error_flag = x; 
      ready_flag = 0; 
     } 
     //don't mess with the flags outside of their 'scope' 
     return 0; 
    } 

С другой стороны, если ошибка и готовые флаги являются взаимоисключающими, вы могли бы использовать байт (или бит внутри байта/регистр), чтобы указать готовность или состояние ошибки.

0 для ошибки, 1 для не готов/безошибочной и 2 для готовых/безошибочное (или -1, 0, 1, безотносительно)

IIRC, стандартный набор 8051 инструкция Безразлично» t работают на единичных битах, поэтому использование целого байта для (разных) флагов не должно давать вам огромный успех.

+1

8051 имеет диапазон адресов памяти, которые могут быть адресованы битами. Внутренние байты памяти 20-2F отображаются в битовое адресное пространство. Биты устанавливаются с помощью setb и clr; а jb, jbc и jnb - логические тесты. Итак, «setb 00h» совпадает с «orl 20h, # 0x01», кроме более эффективного. – daotoad

+0

Хе-хе, жить и учиться. Когда я использовал 8051, у меня было абсурдное количество 64 КБ ROM и 2 КБ ОЗУ. При этом я не стал искать такую ​​эффективность (проект использовал максимум 59 кБ/1,5 кБ) = D –

+0

Да, мне тоже нравится такой проект. Таким образом, я могу писать для удобочитаемости и здравомыслия, и не нужно тщательно взвешивать каждый бит и байт. – daotoad

3

Я сделал свой Ph.D. по аналогичной проблеме на Java. Я могу сказать вам одно, чего вам не следует делать: не полагайтесь на документацию, потому что тогда вы зависите от того, кто действительно ее читает. Вам нужно добавить подсказку в имени метода, чтобы указать, что пользователь должен прочитать документы, чтобы узнать о побочных эффектах. Если вы выберете что-то и согласитесь с ним, вы, вероятно, проявите большую вероятность.

3

Если вы хотите просто упомянуть, что функция влияет на глобальную переменную (-ы), то может помочь простой (венгерский) префикс.

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

/************************************************************************* 
    * FUNCTION : <function_name> 
    * DESCRIPTION : <function description> 
    * PARAMETERS : 
    * Param1 - <Parameter-1 explanation> 
    * Param2 - <Parameter-2 explanation> 
    * Param3 - <Parameter-3 explanation> 
    * RETURN  : <Return value and type> 
    * GLOBAL VARIABLES USED: 
    * Global1 - <Global-1 explanation> 
    * Global2 - <Global-2 explanation> 
    * Global3 - <Global-3 explanation> 
    *************************************************************************/ 
2

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


unsigned char _a_function(void); 

#define A_Function(ret_val) (*(ret_val) = _a_function(), !global_error_flag) 

... 
unsigned char var; 
/* call the function */ 
if (!A_Function(&var)) 
{ 
    /* error! */ 
} 
else 
{ 
    /* use var */ 
    var++; 
} 

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

-2

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

unsigned char A_Function (bit *p_error_flag, bit *p_data_ready_flag) 
{ 
    ... 
} 
+3

Я работаю над системой с 8 8-битными регистрами и всего 256 байт памяти. 8 регистров используют 8 из 256 байт памяти. Использование указателей потребляет ресурсы, которые недоступны. Даже пропущенные неиспользуемые указатели бесполезны. В противном случае я бы использовал указатели. – daotoad

0

Если вы еще не сделали этого , вы также можете проверить sdcc project on sourceforge, это компилятор C, специально предназначенный для использования для встроенной разработки, которая также нацелена на 8051, кроме того, компилятор поддерживает ряд пользовательских, целевых и нестандартных встроенных компиляторов для различных Кроме того, я лично нашел, что команда разработчиков была очень открытой и отзывчивой о идеях новых улучшений и других связанных с ними запросов функций.

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

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