Используйте #ifdefs и #define для дополнительного превращения вызова функции в комментарий

Это не полный ответ, но какое-то объяснение.

Прежде всего,

, если число месяца меньше 3, year- = 1 и month + = 12

, используется для эффективного начала года с марта перемещая крайне нерегулярный февраль к концу. На самом деле это то, как этот календарь был изначально разработан, который вы все еще можете увидеть в названиях некоторых месяцев, таких как октябрь или декабрь (вы, вероятно, слышали, что октябрь = 8 и декабрь = 10)

Удар 365*year + year/4 - year/100 просто обрабатывает високосные годы.

Часть day также понятна.

Теперь давайте удалим биты, которые не имеют значения, когда мы вычтем два значения и получим это значение для month

30*month + (3*month - 2)/5

. Я не знаю логику, как это было получено (у меня есть только предположение в конце) но я могу сказать, почему это работает. Бит 30*month очевиден. И теперь, когда мы переместили февраль на его последнюю позицию, все месяцы в середине года имеют либо 30, либо 31 день. Запишем их:

  • Март - 31 - +1
  • Апр - 30 - +0
  • Май - 31 - +1
  • Июнь - 30 - +0
  • июль - 31 - +1
  • август - 31 - +1
  • сентябрь - 30 - +0
  • октябрь - 31 - +1
  • ноябрь - 30 - +0
  • декабрь - 31 - +1
  • январь - 31 - +1

мы не волнует февраль, так как после него нет месяцев (мы заботились об этом раньше). Мы заботимся только об этом +1 дне со следующего месяца после этого!

Так что нам сейчас нужна некоторая формула, которая бы соответствовала этому распределению +1 и +0. И кажется, что значение

(3*month - 2)/5

с целочисленным делением делает именно это. Вы можете легко проверить это вручную.

Вероятно, способ придумать эту идею состоял в том, чтобы заметить, что год (кроме февраля) следует за следующим 5-месячным циклом

+1 +0 +1 +0 +1

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

15
задан Deduplicator 30 March 2015 в 15:12
поделиться

11 ответов

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

#ifdef SOMETHING
#define foo(x)
#else
#define foo(x) MyFunction(x)
#endif

, Если Ваша функция имеет несколько аргументов, то:

#ifdef SOMETHING
#define foo(x,y,z)
#else
#define foo(x,y,z) MyFunction(x,y,z)
#endif

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

#ifdef SOMETHING
#define foo(...)
#else
#define foo(...) MyFunction(__VA_ARGS__)
#endif

основания, которые я видел такого рода вещь, используемую на практике, состоят в том, чтобы избавиться от входа функций от сборки конечных версий. Однако см. также Отдельный ' debug' и ' release' сборки? , в которых людях вопрос, должны ли Вы даже , имеют различные сборки.

<час>

, С другой стороны, вместо того, чтобы переопределить вызов функции как ничто, комментарий Jonathan к этому ответу предложил делать что-то как следующее:

#ifdef SOMETHING
#define foo(...) do { if (false) MyFunction(__VA_ARGS__) } while (0)
#else
#define foo(...) do { if (true) MyFunction(__VA_ARGS__) } while (0)
#endif

обоснование для того, чтобы сделать это - то, так, чтобы вызов функции всегда компилировался (таким образом, это не оставят с бесплатными ошибками как ссылки на удаленные переменные), но только звонил при необходимости: посмотрите Kernighan & Пика Практика Программирования и также Центр космических полетов имени Годдарда, программируя стандарты .

Из debug.h файла (происходящий с 1990 и поэтому не использующий __VA_ARGS__):

/*
** Usage:  TRACE((level, fmt, ...))
** "level" is the debugging level which must be operational for the output
** to appear. "fmt" is a printf format string. "..." is whatever extra
** arguments fmt requires (possibly nothing).
** The non-debug macro means that the code is validated but never called.
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
*/
#ifdef DEBUG
#define TRACE(x)    db_print x
#else
#define TRACE(x)    do { if (0) db_print x; } while (0)
#endif /* DEBUG */

С C99, больше нет потребности в двойном приеме круглых скобок. Новый код не должен использовать его, если совместимость C89 не является проблемой.

23
ответ дан 1 December 2019 в 01:00
поделиться

Возможно, более легкий способ сделать это должно было бы условно опустить тело функции?

void MyFunction() {
#ifndef SOMETHING
    <body of function>
#endif
}

, Если Вы конкретно не хотите, чтобы вызов функции был сделан вообще, это походит на очевидный способ для достижения цели.

5
ответ дан 1 December 2019 в 01:00
поделиться

К сожалению, текущая версия C++ не поддерживает variadic макросы.

Однако можно сделать это:

#ifdef SOMETHING
#define foo
#else
#define foo(args) MyFunction args
#endif

// you call it with double parens:
foo((a, b, c));
3
ответ дан 1 December 2019 в 01:00
поделиться

Если, в случае Вы не хотите названное нечто, Вы определяете его как:

void foo() {}

любые вызовы к нечто () должны быть оптимизированным путем.

2
ответ дан 1 December 2019 в 01:00
поделиться

Что относительно чего-то вдоль этих строк:

#ifdef NDEBUG
#define DEBUG(STATEMENT) ((void)0)
#else
#define DEBUG(STATEMENT) (STATEMENT)
#endif

Вы использовали бы его как это для входа сообщений отладки:

DEBUG(puts("compile with -DNDEBUG and I'm gone"));
<час>

А неуниверсальная версия для отформатированного вывода с дополнительной отладочной информацией с помощью макросов C99 variadic и __func__ идентификатор мог быть похожим на это:

#ifdef NDEBUG
#define Dprintf(FORMAT, ...) ((void)0)
#define Dputs(MSG) ((void)0)
#else
#define Dprintf(FORMAT, ...) \
    fprintf(stderr, "%s() in %s, line %i: " FORMAT "\n", \
        __func__, __FILE__, __LINE__, __VA_ARGS__)
#define Dputs(MSG) Dprintf("%s", MSG)
#endif

Вот то, как Вы использовали бы их макросы:

Dprintf("count = %i", count);
Dputs("checkpoint passed");
2
ответ дан 1 December 2019 в 01:00
поделиться

Нет, C и Стандарты C++ говорят, что Вы не можете #define что-то, чтобы быть комментарием, таким образом

#define foo //

не будет работать.

1
ответ дан 1 December 2019 в 01:00
поделиться

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

// pre/post increment inside method call:
MyFunction(i++); 

// Function call (with side effects) used as method argument: 
MyFunction( StoreNewUsernameIntoDatabase(username) ); 

, Если необходимо было отключить MyFunction путем простого высказывания:

#define MyFunction(x) 

затем побочные эффекты, которые ожидали вызывающие стороны, уйдут, и их код повредился бы и был бы довольно трудным отладить. Мне нравится "sizeof" предложение выше, и мне также нравится, когда предложение просто отключает тело MyFunction () через #ifdef, хотя это означает, что все вызывающие стороны получают ту же версию MyFunction (). От Вашего проблемного оператора я предполагаю, что это не на самом деле, что Вы хотите.

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

#ifdef SOMETHING 
#define MyFunction(x) NoOp_MyFunction(x) 

int NoOp_MyFunction(x) { } 
#endif 

Вы могли даже включать реализацию NoOp_MyFunction () в источнике & заголовки для MyFunction (). У Вас также есть гибкость для добавления дополнительного входа или отладочной информации в NoOp_MyFunction () также.

2
ответ дан 1 December 2019 в 01:00
поделиться

Что относительно того, чтобы окружить каждый вызов к myFunction с

#ifdef SOMETHING
myFunction(...);
#endif

?

0
ответ дан 1 December 2019 в 01:00
поделиться

Если я помню правильно, необходимо смочь к #define макрос ни к "чему", и это заставит компилятор игнорировать тот вызов

#define foo()

foo();    // this will be ignored
0
ответ дан 1 December 2019 в 01:00
поделиться

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

#ifdef SOMETHING
#define foo (1) ? ((void) 0) : (void)
#else
#define foo MyFunction
#endif

Поэтому, если у Вас есть строка кода:

foo( "this is a %s - a++ is %d\n", "test", a++);

это закончится после шага предварительной обработки как также:

MyFunction( "this is a %s - a++ is %d\n", "test", a++);

или

(1) ? ((void) 0) : (void)( "this is a %s - a++ is %d\n", "test", a++);

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

вариант А этого - что-то близко к какой ChriSW и предложенный Jonathan Leffler:

#ifdef SOMETHING
#define foo if (0) MyFunction
#else
#define foo if (1) MyFunction
#endif

Это немного отличается в этом, это не требует, чтобы компилятор поддерживал variadic макросы (__VA_ARGS__).

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

Примечание потенциал для проблем - особенно, если параметры в вызове производят побочные эффекты (это - общая проблема с макросами - не только этот взлом). В примере, эти a++ будет оценен, только если SOMETHING определяется в сборке, иначе это не. Таким образом, если код после вызова зависит от значения a, чтобы быть увеличенным, одна из сборок имеет ошибку.

1
ответ дан 1 December 2019 в 01:00
поделиться
#ifdef SOMETHING
#define foo sizeof
#else
#define foo MyFunction
#endif

я предполагаю, что нечто printf функция стиля? Так или иначе это не будет работать с нулевой функцией параметра, но если бы это имело место, то Вы уже знали бы, что сделать. Если Вы действительно хотите быть анальными, можно использовать (void)sizeof, но это является, вероятно, ненужным.

1
ответ дан 1 December 2019 в 01:00
поделиться