Ответ 1
Я бы представил макрос STATIC_ASSERT и поместил все ваши предположения в такие утверждения.
Я пишу C-код, который делает определенные предположения о реализации, такие как:
char
- 8 бит.>>
по целым символам sign-extends.double
- это удваивает IEEE-754 и может быть пустым для строки и из uint64_t
с ожидаемым результатом.size_t
и обратно без потери информации.char*
такая же, как обычная арифметика на size_t
.void*
и обратно без потери информации.Теперь все это вещи, которые стандарт C не гарантирует, поэтому, строго говоря, мой код не переносится. Тем не менее, они оказываются истинными на архитектурах и ABI, которые я нахожу в настоящее время, и после тщательного рассмотрения я решил, что риск, который им не удастся удержать в какой-либо архитектуре, которую мне нужно настроить в будущем, является приемлемо низким по сравнению с прагматическими преимуществами, которые я получаю сейчас от сделанных предположений.
Вопрос: как лучше всего документировать это решение? Многие из моих предположений сделаны практически всеми (не-октетные char
s? Или знаковые значения целых чисел в будущей, коммерчески успешной архитектуре?). Другие более спорны - наиболее рискованно, вероятно, является одним из указателей на функции. Но если я просто перечислил все, что я предполагаю, помимо того, что дает мне стандарт, глаза читателя просто затуманиваются, и он может не заметить тех, которые на самом деле имеют значение.
Итак, есть ли какой-то известный набор предположений о том, что я являюсь "несколько ортодоксальной" архитектурой, которую я могу включить в качестве ссылки, а затем только явным образом документирую, где я выхожу за пределы этого? (Фактически такой "профиль" будет определять новый язык, который является надмножеством C, но он может не признать, что во многих словах - и это может быть и не прагматически полезным способом думать об этом).
Уточнение. Я ищу короткий документ для документирования своих вариантов, а не для автоматического тестирования, соответствует ли данный компилятор моим ожиданиям. Последнее, очевидно, тоже полезно, но не решает все. Например, если бизнес-партнер свяжется с нами, говоря: "Мы создаем устройство на базе нового чипа G2015 Google, будет ли ваше программное обеспечение работать на нем?" - тогда было бы хорошо иметь возможность ответить "мы еще не работали с этой аркой, но это не должно быть проблемой, если у нее есть компилятор C, который удовлетворяет такому-то".
Уточнить еще больше, поскольку кто-то проголосовал за закрытие как "не конструктивный": я не ищу здесь обсуждения, просто для указателей на фактические, существующие, официальные документы, которые могут упростить мою документацию включен в качестве ссылки.
Я бы представил макрос STATIC_ASSERT и поместил все ваши предположения в такие утверждения.
К сожалению, не только существует недостаток стандартов для диалекта 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
, но если тенденции продолжатся, они станут все более и более необходимыми.
В большинстве документации для компилятора есть раздел, описывающий конкретное поведение зависимых от реализации функций. Можете ли вы указать на этот раздел документов gcc или msvc, чтобы описать ваши предположения?
Вы можете написать файл заголовка "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" по-другому:
Таким образом, теги [T] [S] [#] и т.д. предназначены для интерпретации парсером, который преобразует любой комментарий в текстовую строку HTML (например) и генерирует <h1></h1>, <b></b>
(или что-то другое вы хотите), когда появляется тег.
Если вы храните синтаксический анализатор как простую и маленькую программу, это может дать вам короткую руку для обработки такого рода документации.