Ответ 1
существует ли какой-либо эффективный стандартно-совместимый способ разрешить всем трем функциям использовать один и тот же буфер, не требуя, чтобы все данные копировались между вызовами функций? Я сомневаюсь, что авторы правил сглаживания C предполагали, что такая вещь должна быть сложной, но для современных компиляторов модно считать, что ничего, написанное через long *, не будет считаться длинным *, даже если эти типы имеют одинаковое представление.
C указывает, что long
и long long
являются разными типами, даже если они имеют одинаковое представление. Независимо от представления, они не являются "совместимыми типами" в смысле, определенном стандартом. Поэтому применяется правило строгого псевдонима (C2011 6.5/7): объект, имеющий эффективный тип long
, не должен иметь сохраненное значение, доступное по l-значению типа long long
, и наоборот. Поэтому, независимо от того, какой тип вашего буфера эффективен, ваша программа демонстрирует поведение undefined, если оно обращается к элементам как типа long
, так и типа long long
.
В то время как я согласен с тем, что авторы стандарта не предполагали, что то, что вы описываете, должно быть сложно, у них также нет особого намерения сделать это легко. Они, прежде всего, обеспокоены определением поведения программы таким образом, чтобы максимально возможное было инвариантно относительно всех свобод, разрешенных для реализации, и среди этих свобод есть то, что long long
может иметь другое представление, чем long
. Поэтому никакая программа, которая полагается на них с одинаковым представлением, может быть строго соответствующей, независимо от природы или контекста этой зависимости.
Тем не менее, похоже, должен существовать стандартный способ эффективного выполнения такой задачи. Есть?
Нет. Эффективным типом буфера является его объявленный тип, если он имеет один или иным образом определяется способом, в котором было установлено его сохраненное значение. В последнем случае это может измениться, если записано другое значение, но любое заданное значение имеет только один эффективный тип. Каким бы ни был его эффективный тип, строгое правило псевдонимов не позволяет получить доступ к значению через lvalues как типа long
, так и типа long long
. Период.
Отключение псевдонимов на основе типов - это, конечно же, один из подходов к созданию такого кода. Любой достойный компилятор должен это допускать, и он избежит многих других возможных ошибок.
В самом деле, этот или какой-то другой подход, специфичный для реализации, возможно, включая Just Just Works, - это ваши единственные альтернативы для совместного использования одних и тех же данных между тремя функциями, которые вы представляете без копирования.
Обновление:
При некоторых ограниченных обстоятельствах может быть несколько более стандартное решение. Например, с определенными функциями API, которые вы указали, вы можете сделать что-то вроде этого:
union buffer {
long l[BUFFER_SIZE];
long long ll[BUFFER_SIZE];
int64_t i64[BUFFER_SIZE];
} my_buffer;
fill_array(my_buffer.l, BUFFER_SIZE);
munge_array(my_buffer.i64, BUFFER_SIZE);
output_array(my_buffer.ll, BUFFER_SIZE);
(Реквизит @Riley для того, чтобы дать мне эту идею, хотя она немного отличается от его.)
Конечно, это не работает, если ваш API динамически выделяет сам буфер. Обратите внимание, что
-
Программа, использующая этот подход, может соответствовать стандарту, но если она принимает такое же представление для
long
,long long
иint64_t
, то она по-прежнему строго не соответствует, поскольку стандарт определяет, что термин. -
Стандарт немного непоследователен в этом вопросе. Его замечания о разрешении типа punning через a
union
приведены в сноске, а сноски являются ненормативными. Переосмысление, описанное в этой сноске, похоже, противоречит пункту 6.5/7, который является нормативным. Я предпочитаю, чтобы мой критически важный код находился далеко от неопределенностей, таких как это, даже если мы пришли к выводу, что этот подход должен работать, неопределенность дает только то, что связано с ошибками компилятора. -
Довольно известная фигура в поле как-то говорила об этом:
Союзы не полезны [для псевдонимов], независимо от того, что говорят глупые юристы языка, поскольку они не являются общий метод. Профсоюзы работают только для тривиальных и в основном неинтересных случаев, и не имеет значения, что C99 говорит о проблеме, поскольку неприятная вещь, называемая "реальной жизнью", вмешивается.