2013-06-14 2 views
1

Я недавно слышал, что в некоторых случаях программисты считают, что вы никогда не должны использовать литералы в своем коде. Я понимаю, что в некоторых случаях назначение имени переменной для данного номера может быть полезным (особенно с точки зрения обслуживания, если это число используется в другом месте). Однако рассмотрим следующие тематические исследования:Использование литералов, yay/nay в C++

Пример 1: Использование литералов для «специальных» байтовых кодов.

Скажите, что у вас есть оператор if, который проверяет определенное значение, хранящееся (для аргумента), uint16_t. Вот образцы два кода:

Версия 1:

// Descriptive comment as to why I'm using 0xBEEF goes here 
if (my_var == 0xBEEF) { 
    //do something 
} 

Версия 2:

const uint16_t kSuperDescriptiveVarName = 0xBEEF; 
if (my_var == kSuperDescriptiveVarName) { 
    // do something 
} 

Что является "предпочтительным" метод с точки зрения хорошей практики кодирования? Я могу полностью понять, почему вы предпочитаете версию 2, если kSuperDescriptiveVarName используется более одного раза. Кроме того, делает ли компилятор какие-либо оптимизации, чтобы обе версии имели одинаковый исполняемый код? То есть, есть ли последствия для производительности здесь?

Пример 2: Использование sizeof

Я полностью понимаю, что с помощью SizeOf по сравнению с сырым буквальным является предпочтительным для портативности и также читаемость проблем. Учитывайте два примера кода. Сценарий заключается в том, что вы вычисляете смещение в буфере пакетов (массив uint8_t), где первая часть пакета хранится как my_packet_header, что, скажем, uint32_t.

Версия 1:

const int offset = sizeof(my_packet_header); 

Версия 2:

const int offset = 4; // good comment telling reader where 4 came from 

Очевидно, что версия 1 является предпочтительным, но что в случаях, когда у вас есть несколько полей данных, чтобы пропустить? Что делать, если у вас есть следующие вместо:

Версия 1:

const int offset = sizeof(my_packet_header) + sizeof(data_field1) + sizeof(data_field2) + ... + sizeof(data_fieldn); 

Version 2:

const int offset = 47; 

Что является предпочтительным в этом случае? Имеет ли смысл показать все шаги, связанные с вычислением смещения, или имеет ли смысл буквальное использование здесь?

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

+0

Причина для меня: предположим, что вы хотите использовать 0xBEEF в более чем одном месте, которое вам нужно было бы скопировать-вставить, что почти всегда является признаком нарушения DRY. Если вы используете константу вместо этого, вы просто повторно используете константу, и на данный момент вы меняете BEEF на DEADBEEF, все довольны, так как они получают обновленное значение (за исключением говядины с тех пор, теперь он мертв :) – stijn

ответ

3

Какая «предпочтительная» методика с точки зрения хорошей практики кодирования? Я могу полностью понять, почему вы предпочитаете версию 2, если kSuperDescriptiveVarName используется более одного раза.

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

Против того, что переменная const означает, что все программисты, изучающие код, будут задаваться вопросом, используется ли она где-нибудь еще, учитывая ее, когда они проверяют остальную часть области, в которой она объявлена, и т. Д. - менее ненужные вещи чтобы помнить, что более надежным будет понимание важных частей кода.

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

Кроме того, делает ли компилятор какие-либо оптимизации, чтобы обе версии имели одинаковый исполняемый код? То есть, есть ли последствия для производительности здесь?

В оптимизированном коде нет никаких последствий для производительности.

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

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

Какой из них [для расчета смещений в структуре]? Имеет ли смысл показать все шаги, связанные с вычислением смещения, или имеет ли смысл буквальное использование здесь?

offsetof макрос (#include <cstddef>) лучше для этого ... снова снижение нагрузки на техническое обслуживание.С этот + то, что подходит, вы проиллюстрируете, если компилятор решит использовать любое дополнение, ваше смещение будет неправильным, и вам придется исправлять его каждый раз, когда вы добавляете или удаляете поле.

Игнорирование вопросов смещения и просто рассмотрение вашего этого + этого пример в качестве иллюстрации более сложного значения для присвоения, опять же это балансирующий акт. Вы определенно хотели бы, чтобы здесь было указано какое-то объяснение/комментарий/документация re re (здесь вы работаете с двоичным размером более ранних полей? Вычисляете смещение следующего поля?), Намеренно пропуская некоторые поля, которые могут быть не нужны для предполагаемого использования, или это случайный? ...). Тем не менее, названной константе может быть достаточно документации, поэтому, вероятно, неважно, каким образом вы опережаете ....

1

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

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

0

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

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

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

2

В каждом примере, который вы перечисляете, я бы назвал это имя.

В вашем первом примере вы почти наверняка использовали это специальное число 0xBEEF как минимум дважды - один раз, чтобы написать его и один раз, чтобы сделать ваше сравнение. Если вы его не пишете, этот номер по-прежнему является частью контракта с кем-то другим (возможно, определение формата файла).

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

Есть некоторые случаи, когда я предпочитаю литералы по именованным константам. Это всегда случаи, когда имя больше не имеет смысла, чем число. Например, у вас есть игровая программа, играющая в игру в кости (возможно, Yahtzee), где есть конкретные правила для конкретных бросков кубиков. Вы можете определить константы для One = 1, Two = 2 и т. Д. Но зачем беспокоиться?

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