Существует ли компилятор C, которому не удается скомпилировать это?

21
задан Peter Mortensen 22 January 2014 в 21:22
поделиться

13 ответов

Солярис 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 (), но компиляторы не сотрудничали.

22
ответ дан 29 November 2019 в 06:20
поделиться
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
}

Немного менее читаемый и не такая проверка, но возможно еще быстрее, нет?

13
ответ дан 29 November 2019 в 06:20
поделиться

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

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;
}
11
ответ дан 29 November 2019 в 06:20
поделиться

Я только знаю то, что Стандарт C говорит об этом (C99):

значение целочисленной символьной константы, содержащей больше чем один символ (например, 'ab'), или содержащей последовательность символов или escape-последовательность, которая не отображается на однобайтовый символ выполнения, является реализацией-deп¬Ѓned. Если целочисленная символьная константа содержит отдельный символ или escape-последовательность, ее значение является тем, которое заканчивается, когда объект с символом типа, значение которого является значением отдельного символа или escape-последовательности преобразовывается для ввода интервала

(6.4.4.4/10 взятый из проекта)

, Таким образом, это - определенная реализация. Значение не гарантируется, что это работает, то же везде, но поведение должно быть зарегистрировано реализацией. Например, если int только 16 битов шириной в конкретной реализации, то 'Jan/' не может быть больше представлен как Вы, предназначают это (char, должны быть по крайней мере 8 битов, в то время как символьный литерал всегда имеет тип int).

10
ответ дан 29 November 2019 в 06:20
поделиться
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;
6
ответ дан 29 November 2019 в 06:20
поделиться

Существует по крайней мере 3 вещи, которые мешают этой программе быть портативной:

  1. Мультисимвольные константы определяются реализацией, таким образом, различные компиляторы могут обработать их по-другому.
  2. байт А может составить больше чем 8 битов, существует много аппаратных средств, где самая маленькая адресуемая единица памяти равняется 16 или даже 32 бита, Вы часто находите это в DSPS, например. Если байт составит больше чем 8 битов затем то так будет char, так как char по определению один байт длиной; Ваша программа не будет функционировать правильно в таких системах.
  3. Наконец, существует много машин, где int только 16 битов (который является самым маленьким размером, допускал интервал) включая встроенные устройства и машины прежней версии, Ваша программа перестанет работать на этих машинах также.
4
ответ дан 29 November 2019 в 06:20
поделиться

CVI 8.5 Национального Инструмента для компилятора Windows перестал работать на Вашем исходном коде с несколькими предупреждениями:

  Warning: Excess characters in multibyte character literal ignored.

и ошибки формы:

  Duplicate case label '77'.

Это успешно выполняется на коде Jonathan.

4
ответ дан 29 November 2019 в 06:20
поделиться

Я получаю предупреждения, но никакие ошибки (gcc). Кажется, компилирует и работает прекрасный. май не работают на системы с обратным порядком байтов, хотя!

я не предложил бы этот метод, все же. Возможно, Вы можете xor вместо или-сдвига, для создания единственного байта. Затем используйте оператор выбора на байте (или, быстрее, используйте LUT первых битов N).

2
ответ дан 29 November 2019 в 06:20
поделиться

То, что четыре символьных константы эквивалентны конкретному 32-разрядному целому числу, нестандартно функция, часто замечаемая на компиляторах для MS Windows и компьютеров Mac (и PalmOS, AFAICR).

В системах тезисов четыре символьных строки являются наиболее часто используемыми как тег для идентификации блоков файлов данных, или как приложение / идентификатор типа данных (например, "APPL").

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

1
ответ дан 29 November 2019 в 06:20
поделиться

Я был бы верная любовь для наблюдения профилирования, которое показывает , это является старшим значащим узким местом, но в любом случае если Вы собираетесь вытянуть что-то вроде этого, используйте объединение вместо 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 $ 
0
ответ дан 29 November 2019 в 06:20
поделиться

Проблемы размера машинного слова в стороне, Ваш компилятор может продвинуть, вводит [я] к отрицательному целому числу, которое просто установит верхние биты inputInt с или операции, таким образом, я предложу, чтобы Вы были явными о со знаком из символьных переменных.

, Но с тех пор в США, никто не заботится о 8-м бите, это - вероятно, надуманный вопрос для Вас.

0
ответ дан 29 November 2019 в 06:20
поделиться

компилятор Comeau

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) {
             ^
1
ответ дан 29 November 2019 в 06:20
поделиться

Как упомянуто другими, тот код бросает набор предупреждений и вероятно не безопасен от порядка байтов.

Был Ваш исходный синтаксический анализатор даты, написанный от руки также? Вы попробовали strptime (3)?

0
ответ дан 29 November 2019 в 06:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: