Какова семантика C99, “ограничивают” относительно указателей на указатели?

Полезный подход для сериализации экземпляров несериализуемых классов (или по крайней мере подклассы) известен Последовательный Прокси. По существу Вы реализуете writeReplace для возврата экземпляра совершенно другого сериализуемого класса, который реализует readResolve для возврата копии исходного объекта. Я записал пример сериализации java.awt. BasicStroke на Usenet

11
задан Mat 2 August 2012 в 18:06
поделиться

3 ответа

Что касается первого вопроса, «да», это будет означать нечто иное, если вы используете оба квалификатора restrict , в частности, указатели также не будут иметь псевдонимов. Что касается того, имеет ли это какое-либо значение: теоретически да, на практике это зависит от оптимизатора.

Что касается второго вопроса, «да», предполагается, что все, к чему осуществляется доступ через указатель строки, осуществляется только через указатель строки.

Вы также можете добавить туда const .

Наконец, если это gcc at -O2, -O3 или -Os, компилятор уже выполняет анализ псевдонимов на основе типов. Я уверен, что это делают и другие компиляторы. Это означает, что ограничение указателей по сравнению с целыми числами уже понятно, оставляя только массивы, которые могли бы хранить друг друга.

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

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

3
ответ дан 3 December 2019 в 11:04
поделиться

Внешнее (второе) ограничение сообщает компилятору, что ни один из массивов указателей (A, B и out) не является псевдонимом. Внутреннее (первое) ограничение сообщает компилятору, что ни один из массивов целых чисел (на которые указывают элементы массивов указателей) не является псевдонимом.

Если вы обращаетесь как к A [0] [col * nrows + row], так и к A [ col] [row], значит, вы нарушаете внутреннее ограничение, поэтому что-то может сломаться.

2
ответ дан 3 December 2019 в 11:04
поделиться

int ** restrict только утверждает, что память, адресованная Out, A и B, не перекрывается (за исключением того, что A и B могут перекрываться, если ваша функция не изменяет ни то, ни другое их). Это означает массивы указателей. Он ничего не утверждает о содержимом памяти, на которую указывают Out, A и B. Сноска 117 в n1124 говорит:

если идентификатор p имеет тип (int ** restrict), тогда выражения указателя p и p + 1 основаны на обозначенный объект ограниченного указателя на p, но выражения указателя * p и p [1] - нет.

По аналогии с const , я подозреваю, что квалификация с restrict дважды подтвердит то, что вы хотите, а именно, что ни одно из значений в массив указывает на перекрывающуюся память. Но, читая стандарт, я не могу доказать себе, что это действительно так. Я считаю, что «Пусть D будет объявлением обычного идентификатора, который предоставляет средства обозначения объекта P как ограниченного указателя на тип T» действительно означает, что для int * restrict * restrict A , тогда A [0] и A [1] являются объектами, обозначенными как ограниченный указатель на int. Но это довольно тяжелый юридический язык.

Я понятия не имею, действительно ли ваш компилятор будет делать что-нибудь с этим знанием, заметьте. Ясно, что может, вопрос в том, реализовано ли это.

Так что я не Я действительно знаю, что вы получили от обычного массива C 2-D, где вы просто выделяете строк * cols * sizeof (int) и индексируете с помощью A [cols * row + col] . Тогда вам явно понадобится только одно использование restrict, и любой компилятор, который что-либо делает с restrict , сможет переупорядочить чтение из A и B через запись в Out. Без restrict , конечно, не может, поэтому, делая то, что вы делаете, вы бросаете себя на милость вашего компилятора. Если он не может справиться с двойным ограничением, только с одним случаем ограничения, то двойная косвенная адресация стоила вам оптимизации.

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

доступ к элементам через A [0] [col * nrows + row] undefined?

Да, если элемент изменен одним из обращений, потому что это делает A [0] псевдонимом для памяти, доступ к которой также осуществляется через A [col] . Было бы хорошо, если бы только A и B были ограниченными указателями, но не если бы A [0] и A [col] были.

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

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

обращается к элементам через A [0] [col * nrows + row] undefined?

Да, если элемент изменен одним из обращений, потому что это делает A [0] псевдонимом для памяти, доступ к которой также осуществляется через A [col]. Было бы хорошо, если бы только A и B были ограниченными указателями, но не если бы A [0] и A [col] были.

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

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

обращается к элементам через A [0] [col * nrows + row] undefined?

Да, если элемент изменен одним из обращений, потому что это делает A [0] псевдонимом для памяти, доступ к которой также осуществляется через A [col]. Было бы хорошо, если бы только A и B были ограниченными указателями, но не если бы A [0] и A [col] были.

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

обращается к элементам через A [0] [col * nrows + row] undefined?

Да, если элемент изменен одним из обращений, потому что это делает A [0] псевдонимом для памяти, доступ к которой также осуществляется через A [col]. Было бы хорошо, если бы только A и B были ограниченными указателями, но не если бы A [0] и A [col] были.

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

обращается к элементам через A [0] [col * nrows + row] undefined?

Да, если элемент изменен одним из обращений, потому что это делает A [0] псевдонимом для памяти, доступ к которой также осуществляется через A [col]. Было бы хорошо, если бы только A и B были ограниченными указателями, но не если бы A [0] и A [col] были.

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

2
ответ дан 3 December 2019 в 11:04
поделиться
Другие вопросы по тегам:

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