C минимальное стандартное требование - PullRequest
0 голосов
/ 18 января 2019

Из стандарта C ИСО / МЭК 9899: 201x 5.1.2.3p6 :

Минимальные требования к соответствующей реализации:

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

Это наблюдаемое поведение программы.

Значение этого абзаца довольно драматично (по крайней мере для меня), как я вижу, этот абзац говорит, что:

(1) Компилятор, который производит то же наблюдаемое поведение, что и абстрактная машина, полностью соответствующая стандарту, является соответствующим компилятором, что означает, что все другие требования и параграфы в стандарте просто лишние (кроме разделы volatiles и 7.21.3), например, соответствующий компилятор может фактически нарушать правила порядка оценок (a && b), если наблюдаемое поведение (летучие компоненты, содержимое файлов и интерактивный вывод) является правильным.

(2) Программа, которая не имеет летучих компонентов, не записывает в файлы и не имеет интерактивного ввода-вывода, является программой, которая фактически ничего не делает, не имеет наблюдаемого поведения и может быть полностью оптимизирована, например, до двух инструкция xor eax, eax чем ret (x86-64 clang 7.0.0) в main.

Я прав или нет, об этом?

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Да, вы правы. Компилятор может делать то, что он хочет, при условии, что наблюдаемое поведение такое же, как и абстрактная машина, которая может выдавать . Но это не драматично само по себе: почему мы заботимся о том, чего нельзя наблюдать? Это точка оптимизации компиляторов.

Пример:

int main() {
    int a;
    for (int i=INT_MAX; i>=0; i--) {
        a = i;
    }
    printf("%d\n", a);
    return 0;
}

Единственное наблюдаемое поведение это то, что он будет печатать 0 за один раз. Таким образом, компилятор может оптимизировать цикл так, чтобы он выглядел так же, как:

int main() {
    printf("%d\n", 0);
    return 0;
}

Что по сути означает, что вы не можете использовать пустые циклы для добавления задержек, потому что их можно было бы оптимизировать без задержки вообще.

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

Второй пример:

int main() {
    struct {
        int a[16];
        int b[16];
    } s;

    for (i=0; i<16; i++) {
        s.a[i] = i;
        s.b[i] = 2 * i;
    }
    for (i=0; i<32; i++) {
        printf(" %d", s.a[i]);      // UB array access past upper bound
    }
    printf("\n");
    return 0;
}

Наивный компилятор должен отображать все числа от 0 до 31, потому что мы знаем, что массивы s.a и s.b должны быть смежными, а арифметика указателей должна давать &(s.b[0]) == &(s.a[16]). Но оптимизирующий компилятор может заметить, что значения s.b никогда не используются в наблюдаемом поведении, если не задействован ни один UB, и он может оптимизировать доступ к массиву s.b и даже оптимизировать член b. Здесь следует ожидать аварийных или случайных значений ... Хуже того, действительно умный компилятор может заметить, что в цикле печати есть прошлые связанные обращения. С этого момента поведение программы не определено, и компилятор может, например, остановить цикл после печати 16-го значения. Нет ошибок, но напечатано только 16 значений ...

0 голосов
/ 18 января 2019
  1. Да, реализация C (не просто компилятор - включены стандартная библиотека, поддержка ссылок и поддержки времени выполнения и / или все, что используется для реализации C), которая производит такое же наблюдаемое поведение 1 как соответствующая абстрактная машина соответствует. Все остальные требования и параграфы в стандарте не являются просто дополнительными. Они определяют поведение абстрактной машины, поэтому они способствуют описанию того, каким должно быть наблюдаемое поведение.

  2. Да, программа, которая не имеет наблюдаемого поведения, может быть оптимизирована для программы, которая просто возвращает. Обратите внимание, что стандарт на самом деле не включает статус выхода в наблюдаемом поведении , поэтому технически xor eax, eax не требуется. Однако это скорее всего случайный дефект в стандарте, а не намерение.

Примечания

1 Поведение программ - не единственное, что требуется в спецификации. Реализации также должны документировать, например, различное поведение, определяемое реализацией. Таким образом, эта гипотетическая реализация C, которая ведет себя идентично некоторой абстрактной машине, также должна включать в себя требуемую документацию.

...