Подтвердить что ты не робот

Существуют ли известные "профили" стандарта C?

Я пишу C-код, который делает определенные предположения о реализации, такие как:

  • char - 8 бит.
  • подписанные интегральные типы - это два дополнения.
  • >> по целым символам sign-extends.
  • целочисленное деление округляет отрицательные отношения к нулю.
  • double - это удваивает IEEE-754 и может быть пустым для строки и из uint64_t с ожидаемым результатом.
  • сравнения с участием NaN всегда оцениваются как false.
  • нулевой указатель - это все нулевые биты.
  • все указатели данных имеют одинаковое представление и могут быть преобразованы в size_t и обратно без потери информации.
  • арифметика указателя на char* такая же, как обычная арифметика на size_t.
  • указатели функций могут быть переведены на void* и обратно без потери информации.

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

Вопрос: как лучше всего документировать это решение? Многие из моих предположений сделаны практически всеми (не-октетные char s? Или знаковые значения целых чисел в будущей, коммерчески успешной архитектуре?). Другие более спорны - наиболее рискованно, вероятно, является одним из указателей на функции. Но если я просто перечислил все, что я предполагаю, помимо того, что дает мне стандарт, глаза читателя просто затуманиваются, и он может не заметить тех, которые на самом деле имеют значение.

Итак, есть ли какой-то известный набор предположений о том, что я являюсь "несколько ортодоксальной" архитектурой, которую я могу включить в качестве ссылки, а затем только явным образом документирую, где я выхожу за пределы этого? (Фактически такой "профиль" будет определять новый язык, который является надмножеством C, но он может не признать, что во многих словах - и это может быть и не прагматически полезным способом думать об этом).

Уточнение. Я ищу короткий документ для документирования своих вариантов, а не для автоматического тестирования, соответствует ли данный компилятор моим ожиданиям. Последнее, очевидно, тоже полезно, но не решает все. Например, если бизнес-партнер свяжется с нами, говоря: "Мы создаем устройство на базе нового чипа G2015 Google, будет ли ваше программное обеспечение работать на нем?" - тогда было бы хорошо иметь возможность ответить "мы еще не работали с этой аркой, но это не должно быть проблемой, если у нее есть компилятор C, который удовлетворяет такому-то".

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

4b9b3361

Ответ 1

Я бы представил макрос STATIC_ASSERT и поместил все ваши предположения в такие утверждения.

Ответ 2

К сожалению, не только существует недостаток стандартов для диалекта C, который объединяет расширения, которые стали стандартами де-факто в 1990-х годах (двухзначные, универсальные указатели и т.д.), но движущиеся тенденции движутся в противоположном направлении. Учитывая следующие требования к функции:

* Accept int parameters x,y,z:
* Return 0 if x-y is computable as "int" and is less than Z
* Return 1 if x-y is computable as "int" and is not less than Z
* Return 0 or 1 if x-y is not computable */

Подавляющее большинство компиляторов в 1990-х годах позволило бы:

int diffCompare(int x, int y, int z)
{ return (x-y) >= z; }

На некоторых платформах, в тех случаях, когда разница между xy не была вычислимой как int, было бы быстрее вычислить "завернутое" значение двух дополнений x-y и сравнить это, в то время как на других это было бы быстрее выполнить вычисление с использованием типа, большего чем int, и сравнить это. Однако к концу 1990-х годов почти каждый компилятор C реализовал вышеупомянутый код, чтобы использовать один из тех из них, который был бы более эффективен на его аппаратной платформе.

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

{ return ((long)x-y) >= z; }

что значительно снизит эффективность на многих платформах, или

{ return x+(INT_MAX+1U)-y >= z+(INT_MAX+1U); }

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

Было бы полезно, если бы были стандартные профили, которые позволяли бы программистам избегать необходимости неприятных ужасных kludges, подобных выше, используя INT_MAX+1U, но если тенденции продолжатся, они станут все более и более необходимыми.

Ответ 3

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

Ответ 4

Вы можете написать файл заголовка "document.h", где вы соберете все свои предположения.
Затем в каждом файле, который вы знаете, что сделаны нестандартные предположения, вы можете #include создать такой файл.
Возможно, "document.h" вообще не будет иметь реальных предложений, а только комментарий и некоторые макросы.

   // [T] DOCUMENT.H
   //

   #ifndef DOCUMENT_H
   #define DOCUMENT_H 
   // [S] 1. Basic assumptions.
   // 
   // If this file is included in a compilation unit it means that
   // the following assumptions are made:
   //      [1] A char has 8 bits.
   // [#]

   #define MY_CHARBITSIZE 8

   //      [2] IEEE 754 doubles are addopted for type: double.
   // ........
   // [S] 2. Detailed information
   //
   #endif

Теги в скобках: [T] [S] [#] [1] [2] обозначают:

* [T]: Document Title
* [S]: Section
* [#]: Print the following (non-commented) lines as a code-block.
* [1], [2]: Numbered items of a list.

Теперь идея состоит в том, чтобы использовать файл "document.h" по-другому:

  • Чтобы проанализировать файл, чтобы преобразовать комментарии в "document.h" в какой-либо документ, пригодный для печати, или некоторый базовый HTML.

Таким образом, теги [T] [S] [#] и т.д. предназначены для интерпретации парсером, который преобразует любой комментарий в текстовую строку HTML (например) и генерирует <h1></h1>, <b></b> (или что-то другое вы хотите), когда появляется тег.

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