Re: Switch statement or array



Nachy wrote:
Good (evening, morning, afternoon)

I have the following construct in my program. Some may remember this
from the first time I posted on C.L.C. a coupla years ago.
Effectively, it's a calendar program. This function takes as arguments
the day of the week of the beginning of the year - in my case, the
upcoming Jewish New Year - and has to add a certain number of days to
get the day of the week on which the first day of any other month
falls. (Sorry, I know that's a bit garbled.)

... ... ...

Good [mor|noo|eve]ning to you, as well. That's right. Nooning.

For sheer fun (?!), here's something using x-macros. Its wild complexity might come in handy if the calendar used is ever reworked...

Also note that months were arbitrarily chosen to be counted from 1 instead of 0; no reason at all.

#ifdef X
#error X already #defined.
#endif

#ifdef MONTHS
#error MONTHS already #defined.
#endif
/* For x-macro productions */
#define MONTHS \
X(january, 31) \
X(february, 28) \
X(march, 31) \
X(april, 30) \
X(may, 31) \
X(june, 30) \
X(july, 31) \
X(august, 31) \
X(september, 30) \
X(october, 31) \
X(november, 30) \
X(december, 31)

/* The order of the months */
#ifdef ENUM_MONTH
#error ENUM_MONTH already #defined.
#endif
#define ENUM_MONTH(month) month_ ## month
#define X(month, days) ENUM_MONTH(month),
enum month {
month_none,
MONTHS
month_last_po,
month_total = month_last_po - 1
};
#undef X
#undef ENUM_MONTH

/* Days in each month */
#ifdef ENUM_DAYS_IN
#error ENUM_DAYS_IN already #defined.
#endif
#define ENUM_DAYS_IN(month) days_in_ ## month
#define X(month, days) ENUM_DAYS_IN(month) = days,
enum days_in {
MONTHS
days_in_dummy = 0
};
#undef X
/* ENUM_DAYS_IN() used below */

/* Days before the start of each month */
#ifdef ENUM_DAYS_BEFORE_PO
#error ENUM_DAYS_BEFORE_PO already #defined.
#endif
#define ENUM_DAYS_BEFORE_PO(month) days_before_ ## month ## _po
#ifdef ENUM_DAYS_BEFORE
#error ENUM_DAYS_BEFORE already #defined.
#endif
#define ENUM_DAYS_BEFORE(month) days_before_ ## month
#ifdef ENUM_DAYS_ENDOF
#error ENUM_DAYS_ENDOF already #defined.
#endif
#define ENUM_DAYS_ENDOF(month) days_endof_ ## month
#define X(month, days) \
ENUM_DAYS_BEFORE_PO(month), \
ENUM_DAYS_BEFORE(month) = ENUM_DAYS_BEFORE_PO(month) - 1, \
ENUM_DAYS_ENDOF(month) = ENUM_DAYS_BEFORE(month) + ENUM_DAYS_IN(month),
enum days_before {
days_before_dummy,
MONTHS
ENUM_DAYS_ENDOF(year_po),
ENUM_DAYS_ENDOF(year) = ENUM_DAYS_ENDOF(year_po) - 1
};
#undef X
#undef ENUM_DAYS_ENDOF
/* ENUM_DAYS_BEFORE used below */
#undef ENUM_DAYS_BEFORE_PO
#undef ENUM_DAYS_IN
#define X(month, days) ENUM_DAYS_BEFORE(month),
static const enum days_before days_before_a[month_total + 2] = {
0, /* No days in month 0. We count from 1. */
MONTHS
0 /* No days in months after the last month. */
};
#undef X
#undef ENUM_DAYS_BEFORE
#undef MONTHS

static int new_month(int month, int new_year, int leap) {
if (month < 1 || month > month_total)
return -1;
return
(new_year + days_before_a[month] + (month > month_february && leap))
% 7;
}

/* Handy for arrays */
#define NUM_OF_ELEMENTS(array_) \
(sizeof (array_) / sizeof *(array_))
#define FOR_EACH_ELEMENT(index_, array_) \
for ((index_) = 0; (index_) < NUM_OF_ELEMENTS(array_); (index_)++)

#include <stdio.h>

int main(void) {
int i;

FOR_EACH_ELEMENT(i, days_before_a)
printf("Days before month #%d: %d\n", i, days_before_a[i]);
printf("Days in a year: %d\n", days_endof_year);
printf("January 1st, 2010 was a Friday\n "
"new_month(month_october, 5, 0) == %d\n",
new_month(month_october, 5, 0));
printf("January 1st, 2009 was a Thursday\n "
"new_month(month_june, 4, 0) == %d\n",
new_month(month_june, 4, 0));
return 0;
}
.