Солярис 10 - SPARC - Компилятор SUN.
Тестовый код:
#include <stdio.h>
static int parseMonth(const char *input) {
int rv=-1;
int inputInt=0;
int i=0;
for(i=0; i<4 && input[i]; i++) {
inputInt = (inputInt << 8) | input[i];
}
switch(inputInt) {
case 'Jan/': rv=0; break;
case 'Feb/': rv=1; break;
case 'Mar/': rv=2; break;
case 'Apr/': rv=3; break;
case 'May/': rv=4; break;
case 'Jun/': rv=5; break;
case 'Jul/': rv=6; break;
case 'Aug/': rv=7; break;
case 'Sep/': rv=8; break;
case 'Oct/': rv=9; break;
case 'Nov/': rv=10; break;
case 'Dec/': rv=11; break;
}
return rv;
}
static const struct
{
char *data;
int result;
} test_case[] =
{
{ "Jan/", 0 },
{ "Feb/", 1 },
{ "Mar/", 2 },
{ "Apr/", 3 },
{ "May/", 4 },
{ "Jun/", 5 },
{ "Jul/", 6 },
{ "Aug/", 7 },
{ "Sep/", 8 },
{ "Oct/", 9 },
{ "Nov/", 10 },
{ "Dec/", 11 },
{ "aJ/n", -1 },
};
#define DIM(x) (sizeof(x)/sizeof(*(x)))
int main(void)
{
size_t i;
int result;
for (i = 0; i < DIM(test_case); i++)
{
result = parseMonth(test_case[i].data);
if (result != test_case[i].result)
printf("!! FAIL !! %s (got %d, wanted %d)\n",
test_case[i].data, result, test_case[i].result);
}
return(0);
}
Результаты (GCC 3.4.2 и Sun):
$ gcc -O xx.c -o xx
xx.c:14:14: warning: multi-character character constant
xx.c:15:14: warning: multi-character character constant
xx.c:16:14: warning: multi-character character constant
xx.c:17:14: warning: multi-character character constant
xx.c:18:14: warning: multi-character character constant
xx.c:19:14: warning: multi-character character constant
xx.c:20:14: warning: multi-character character constant
xx.c:21:14: warning: multi-character character constant
xx.c:22:14: warning: multi-character character constant
xx.c:23:14: warning: multi-character character constant
xx.c:24:14: warning: multi-character character constant
xx.c:25:14: warning: multi-character character constant
$ ./xx
$ cc -o xx xx.c
$ ./xx
!! FAIL !! Jan/ (got -1, wanted 0)
!! FAIL !! Feb/ (got -1, wanted 1)
!! FAIL !! Mar/ (got -1, wanted 2)
!! FAIL !! Apr/ (got -1, wanted 3)
!! FAIL !! May/ (got -1, wanted 4)
!! FAIL !! Jun/ (got -1, wanted 5)
!! FAIL !! Jul/ (got -1, wanted 6)
!! FAIL !! Aug/ (got -1, wanted 7)
!! FAIL !! Sep/ (got -1, wanted 8)
!! FAIL !! Oct/ (got -1, wanted 9)
!! FAIL !! Nov/ (got -1, wanted 10)
!! FAIL !! Dec/ (got -1, wanted 11)
$
Примечание, которое последний тестовый сценарий все еще передал - то есть, он генерировал-1.
Вот пересмотренный - более подробный - версия parseMonth (), который действительно работает то же и под GCC и под компилятором C Sun:
#include <stdio.h>
/* MONTH_CODE("Jan/") does not reduce to an integer constant */
#define MONTH_CODE(x) ((((((x[0]<<8)|x[1])<<8)|x[2])<<8)|x[3])
#define MONTH_JAN (((((('J'<<8)|'a')<<8)|'n')<<8)|'/')
#define MONTH_FEB (((((('F'<<8)|'e')<<8)|'b')<<8)|'/')
#define MONTH_MAR (((((('M'<<8)|'a')<<8)|'r')<<8)|'/')
#define MONTH_APR (((((('A'<<8)|'p')<<8)|'r')<<8)|'/')
#define MONTH_MAY (((((('M'<<8)|'a')<<8)|'y')<<8)|'/')
#define MONTH_JUN (((((('J'<<8)|'u')<<8)|'n')<<8)|'/')
#define MONTH_JUL (((((('J'<<8)|'u')<<8)|'l')<<8)|'/')
#define MONTH_AUG (((((('A'<<8)|'u')<<8)|'g')<<8)|'/')
#define MONTH_SEP (((((('S'<<8)|'e')<<8)|'p')<<8)|'/')
#define MONTH_OCT (((((('O'<<8)|'c')<<8)|'t')<<8)|'/')
#define MONTH_NOV (((((('N'<<8)|'o')<<8)|'v')<<8)|'/')
#define MONTH_DEC (((((('D'<<8)|'e')<<8)|'c')<<8)|'/')
static int parseMonth(const char *input) {
int rv=-1;
int inputInt=0;
int i=0;
for(i=0; i<4 && input[i]; i++) {
inputInt = (inputInt << 8) | input[i];
}
switch(inputInt) {
case MONTH_JAN: rv=0; break;
case MONTH_FEB: rv=1; break;
case MONTH_MAR: rv=2; break;
case MONTH_APR: rv=3; break;
case MONTH_MAY: rv=4; break;
case MONTH_JUN: rv=5; break;
case MONTH_JUL: rv=6; break;
case MONTH_AUG: rv=7; break;
case MONTH_SEP: rv=8; break;
case MONTH_OCT: rv=9; break;
case MONTH_NOV: rv=10; break;
case MONTH_DEC: rv=11; break;
}
return rv;
}
static const struct
{
char *data;
int result;
} test_case[] =
{
{ "Jan/", 0 },
{ "Feb/", 1 },
{ "Mar/", 2 },
{ "Apr/", 3 },
{ "May/", 4 },
{ "Jun/", 5 },
{ "Jul/", 6 },
{ "Aug/", 7 },
{ "Sep/", 8 },
{ "Oct/", 9 },
{ "Nov/", 10 },
{ "Dec/", 11 },
{ "aJ/n", -1 },
{ "/naJ", -1 },
};
#define DIM(x) (sizeof(x)/sizeof(*(x)))
int main(void)
{
size_t i;
int result;
for (i = 0; i < DIM(test_case); i++)
{
result = parseMonth(test_case[i].data);
if (result != test_case[i].result)
printf("!! FAIL !! %s (got %d, wanted %d)\n",
test_case[i].data, result, test_case[i].result);
}
return(0);
}
я хотел использовать MONTH_CODE (), но компиляторы не сотрудничали.
if ( !input[0] || !input[1] || !input[2] || input[3] != '/' )
return -1;
switch ( input[0] )
{
case 'F': return 1; // Feb
case 'S': return 8; // Sep
case 'O': return 9; // Oct
case 'N': return 10; // Nov
case 'D': return 11; // Dec;
case 'A': return input[1] == 'p' ? 3 : 7; // Apr, Aug
case 'M': return input[2] == 'r' ? 2 : 4; // Mar, May
default: return input[1] == 'a' ? 0 : (input[2] == 'n' ? 5 : 6); // Jan, Jun, Jul
}
Немного менее читаемый и не такая проверка, но возможно еще быстрее, нет?
Вы просто вычисляете хеш тех четырех символов. Почему бы не предопределять некоторые целочисленные константы, которые вычисляют хеш таким же образом и используют их? Та же удобочитаемость и Вы не являетесь в зависимости ни от какой реализации определенными особенностями компилятора.
uint32_t MONTH_JAN = 'J' << 24 + 'a' << 16 + 'n' << 8 + '/';
uint32_t MONTH_FEB = 'F' << 24 + 'e' << 16 + 'b' << 8 + '/';
...
static uint32_t parseMonth(const char *input) {
uint32_t rv=-1;
uint32_t inputInt=0;
int i=0;
for(i=0; i<4 && input[i]; i++) {
inputInt = (inputInt << 8) | (input[i] & 0x7f); // clear top bit
}
switch(inputInt) {
case MONTH_JAN: rv=0; break;
case MONTH_FEB: rv=1; break;
...
}
return rv;
}
Я только знаю то, что Стандарт C говорит об этом (C99):
значение целочисленной символьной константы, содержащей больше чем один символ (например, 'ab'), или содержащей последовательность символов или escape-последовательность, которая не отображается на однобайтовый символ выполнения, является реализацией-deп¬Ѓned. Если целочисленная символьная константа содержит отдельный символ или escape-последовательность, ее значение является тем, которое заканчивается, когда объект с символом типа, значение которого является значением отдельного символа или escape-последовательности преобразовывается для ввода интервала
(6.4.4.4/10 взятый из проекта)
, Таким образом, это - определенная реализация. Значение не гарантируется, что это работает, то же везде, но поведение должно быть зарегистрировано реализацией. Например, если int
только 16 битов шириной в конкретной реализации, то 'Jan/'
не может быть больше представлен как Вы, предназначают это (char
, должны быть по крайней мере 8 битов, в то время как символьный литерал всегда имеет тип int
).
char *months = "Jan/Feb/Mar/Apr/May/Jun/Jul/Aug/Sep/Oct/Nov/Dec/";
char *p = strnstr(months, input, 4);
return p ? (p - months) / 4 : -1;
Существует по крайней мере 3 вещи, которые мешают этой программе быть портативной:
char
, так как char
по определению один байт длиной; Ваша программа не будет функционировать правильно в таких системах. int
только 16 битов (который является самым маленьким размером, допускал интервал) включая встроенные устройства и машины прежней версии, Ваша программа перестанет работать на этих машинах также. CVI 8.5 Национального Инструмента для компилятора Windows перестал работать на Вашем исходном коде с несколькими предупреждениями:
Warning: Excess characters in multibyte character literal ignored.
и ошибки формы:
Duplicate case label '77'.
Это успешно выполняется на коде Jonathan.
Я получаю предупреждения, но никакие ошибки (gcc). Кажется, компилирует и работает прекрасный. май не работают на системы с обратным порядком байтов, хотя!
я не предложил бы этот метод, все же. Возможно, Вы можете xor вместо или-сдвига, для создания единственного байта. Затем используйте оператор выбора на байте (или, быстрее, используйте LUT первых битов N).
То, что четыре символьных константы эквивалентны конкретному 32-разрядному целому числу, нестандартно функция, часто замечаемая на компиляторах для MS Windows и компьютеров Mac (и PalmOS, AFAICR).
В системах тезисов четыре символьных строки являются наиболее часто используемыми как тег для идентификации блоков файлов данных, или как приложение / идентификатор типа данных (например, "APPL").
Это - удобство затем для разработчика, которого они могут сохранить такую строку в различные структуры данных, не волнуя по поводу завершения нулевого байта, указателей, и т.д.
Я был бы верная любовь для наблюдения профилирования, которое показывает , это является старшим значащим узким местом, но в любом случае если Вы собираетесь вытянуть что-то вроде этого, используйте объединение вместо 50 цикличных выполнений инструкций и смещения. Вот немного примера программы, я предоставлю Вам право вмещать его в свою программу.
/* union -- demonstrate union for characters */
#include <stdio.h>
union c4_i {
char c4[5];
int i ;
} ;
union c4_i ex;
int main (){
ex.c4[0] = 'a';
ex.c4[1] = 'b';
ex.c4[2] = 'c';
ex.c4[3] = 'd';
ex.c4[4] = '\0';
printf("%s 0x%08x\n", ex.c4, ex.i );
return 0;
}
Вот вывод в качестве примера:
bash $ ./union
abcd 0x64636261
bash $
Проблемы размера машинного слова в стороне, Ваш компилятор может продвинуть, вводит [я] к отрицательному целому числу, которое просто установит верхние биты inputInt с или операции, таким образом, я предложу, чтобы Вы были явными о со знаком из символьных переменных.
, Но с тех пор в США, никто не заботится о 8-м бите, это - вероятно, надуманный вопрос для Вас.
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C99
"ComeauTest.c", line 11: warning: multicharacter character literal (potential
portability problem)
case 'Jan/': rv=0; break;
^
"ComeauTest.c", line 12: warning: multicharacter character literal (potential
portability problem)
case 'Feb/': rv=1; break;
^
"ComeauTest.c", line 13: warning: multicharacter character literal (potential
portability problem)
case 'Mar/': rv=2; break;
^
"ComeauTest.c", line 14: warning: multicharacter character literal (potential
portability problem)
case 'Apr/': rv=3; break;
^
"ComeauTest.c", line 15: warning: multicharacter character literal (potential
portability problem)
case 'May/': rv=4; break;
^
"ComeauTest.c", line 16: warning: multicharacter character literal (potential
portability problem)
case 'Jun/': rv=5; break;
^
"ComeauTest.c", line 17: warning: multicharacter character literal (potential
portability problem)
case 'Jul/': rv=6; break;
^
"ComeauTest.c", line 18: warning: multicharacter character literal (potential
portability problem)
case 'Aug/': rv=7; break;
^
"ComeauTest.c", line 19: warning: multicharacter character literal (potential
portability problem)
case 'Sep/': rv=8; break;
^
"ComeauTest.c", line 20: warning: multicharacter character literal (potential
portability problem)
case 'Oct/': rv=9; break;
^
"ComeauTest.c", line 21: warning: multicharacter character literal (potential
portability problem)
case 'Nov/': rv=10; break;
^
"ComeauTest.c", line 22: warning: multicharacter character literal (potential
portability problem)
case 'Dec/': rv=11; break;
^
"ComeauTest.c", line 1: warning: function "parseMonth" was declared but never
referenced
static int parseMonth(const char *input) {
^
Как упомянуто другими, тот код бросает набор предупреждений и вероятно не безопасен от порядка байтов.
Был Ваш исходный синтаксический анализатор даты, написанный от руки также? Вы попробовали strptime (3)?