Противоположное ключевое слово ограничения в C?

Поскольку строгие псевдонимы могут помочь компилятору лучше оптимизировать, C99 представил ключевое слово restrict, которое можно использовать в качестве квалификатора переменной, если программисты гарантируют, что к ней не будет доступа через указатель на другой тип. Однако приведение типов между разными типами неизбежно по нескольким причинам, и это заставит компилятор предположить, что один указатель не является псевдонимом другого. Таким образом, метод обхода заключается в отключении глобальной строгой оптимизации псевдонимов путем передачи -fno-strict-aliasing (флаг GCC). Это совершенно бессмысленно, потому что может быть только два указателя, которые не должны быть полностью оптимизированы. Следовательно, почему бы не ввести противоположное ключевое слово restrict, которое сообщает компилятору, что не предполагается, что эти два указателя указывают на разные адреса. Это чем-то похоже на то, что делает volatile, и это говорит компилятору, что эта переменная сильно изменилась, поэтому обращайтесь с ними особым образом. Можно ли создать такое ключевое слово?

EDIT: есть способ решить эту проблему. См. яно комментарий ниже.


person Kevin Dong    schedule 07.09.2016    source источник
comment
strict aliasing не является гарантией того, что к чему-то не будет доступа через более чем один указатель — просто к нему не будет доступа (как правило) через указатель на другой тип. restrict отличается.   -  person Dmitri    schedule 07.09.2016
comment
У вас есть конкретный MVCE?   -  person    schedule 07.09.2016
comment
Я реализую связанный список XOR, который будет приводить два разных типа указателей. Это приводит к тому, что GCC сбивается с толку и создает исполняемые файлы segfault без установки флага -fno-strict-aliasing. Я думаю, что отключать глобальную оптимизацию очень жаль.   -  person Kevin Dong    schedule 07.09.2016
comment
@KevinDong Мне было бы интересно увидеть код, который вызывает ошибку. Не могли бы вы опубликовать?   -  person cxw    schedule 07.09.2016
comment
В настоящее время код действительно огромен и сложен. Мне может понадобиться некоторое время, чтобы очистить его. ;-(. Я могу опубликовать MVCE, если чистка будет сделана.   -  person Kevin Dong    schedule 07.09.2016
comment
Псевдонимы указателей, потому что указатели одновременно указывают на один и тот же объект. Вы уверены, что это обязательно так? Например. вы помещаете псевдонимы указателей в разные области, так что, хотя они указывают на одно и то же, они не указывают на него одновременно?   -  person user3528438    schedule 07.09.2016
comment
@user3528438 user3528438 Это необходимо при реализации связанного списка XOR с двумя контрольными узлами с указателями, а не самими узлами, для уменьшения использования памяти.   -  person Kevin Dong    schedule 07.09.2016
comment
почему бы не ввести противоположное ключевое слово ограничения, которое сообщает компилятору, что не предполагается, что эти два указателя указывают на разные адреса. --› Разве это не результат того, что restrict не кодируется?   -  person chux - Reinstate Monica    schedule 07.09.2016
comment
@KevinDong Возможно, вы могли бы использовать атрибут __may_alias__ GCC для решения проблемы.   -  person Ian Abbott    schedule 07.09.2016
comment
@chux Не совсем. Оптимизация GCC создаст ошибочный код.   -  person Kevin Dong    schedule 07.09.2016
comment
Итак, вы хотите, чтобы ключевое слово GCC выборочно отменяло флаг компилятора GCC. Может быть, GCC #pragma подойдет? Лучше, чем добавление языка.   -  person chux - Reinstate Monica    schedule 07.09.2016
comment
@IanAbbott Спасибо за информацию, но, похоже, это не работает в моем коде. ;-(   -  person Kevin Dong    schedule 07.09.2016
comment
@KevinDong Я почему-то сомневаюсь, что это твоя настоящая проблема. Я настоятельно рекомендую искать в вашем коде неопределенное поведение. Говоря о списке xor, вы имеете в виду двусвязный список, в котором указатель на предыдущий и следующий узел хранится с помощью xor в одном указателе? Вы используете uintptr_t для этого?   -  person Daniel Jour    schedule 07.09.2016
comment
@DanielJour Да. Вместо этого я использую (uintptr_t)(void*). Проблема возникает вокруг тела списка и двух контрольных узлов, которые объявлены с типом struct node*, а не void*.   -  person Kevin Dong    schedule 07.09.2016
comment
Возможное решение состоит в том, чтобы обернуть все типы указателей, которые вы будете использовать, в union, а затем использовать соответствующий член этого union в соответствующее время. См. stackoverflow.com/questions/98650/< /а>   -  person yano    schedule 07.09.2016
comment
@yano Великолепно! Это то, что мне нужно. ;-) Большое спасибо.   -  person Kevin Dong    schedule 07.09.2016
comment
@yano После некоторых незначительных исправлений мой код может быть скомпилирован и выполнен правильно без -fno-strict-aliasing и получить некоторое повышение производительности. Спасибо еще раз.   -  person Kevin Dong    schedule 07.09.2016
comment
Таким образом, метод обхода состоит в том, чтобы отключить глобальную строгую оптимизацию псевдонимов — это функция стандартного C, а не оптимизация. Лучший обходной путь — не писать код, нарушающий правило.   -  person M.M    schedule 07.09.2016
comment
@M.M: Термин C используется для обозначения двух языков: семантически мощного, изобретенного Деннисом Ритчи, и семантически ослабленной версии, которая стала популярной. Учитывая, что семантика первого была стабильной в течение десятилетий, в то время как семантика второго размывается, я предпочитаю ориентироваться на первый для любого кода, который выиграл бы от каламбура. При использовании -fno-strict-aliasing выигрыш в производительности от использования квалификатора restrict, когда это возможно (или стоимость его неиспользования), увеличивается, но если код использует restrict правильно, диалект -fno-strict-alising...   -  person supercat    schedule 08.09.2016
comment
@MM: ... часто будет иметь базовую производительность почти такую ​​​​же, как у диалекта со строгим псевдонимом; в тех случаях, когда каламбур может обеспечить прирост производительности, он может более чем компенсировать потери от -fno-strict-aliasing.   -  person supercat    schedule 08.09.2016


Ответы (1)


Учитывая код:

int foo(int * restrict p)
{
  *p = 3;
  someOutsideFunction();
  return *p;
}

компилятор имеет право предположить, что пока p находится в области видимости, ни один объект, написанный с использованием *p, не будет доступен каким-либо другим способом, кроме как через указатель, который скопирован или иным образом "получен" из p. Другие указатели на объект могут существовать где-то еще во вселенной, но до тех пор, пока foo не вернется, ни один из них нельзя будет использовать для доступа к *p. Следовательно, компилятор может заменить вышеуказанное на

int foo(int * restrict p)
{
  someOutsideFunction();
  *p = 3;
  return 3;
}

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

Если someOutsideFunction может - без ведома компилятора, обрабатывающего foo - включить ключевое слово, которое ведет себя как противоположное restrict, и может позволить ему получить доступ к объекту, указанному p [получение указателя на этот объект из глобальной переменной или другими подобными средствами ], что сделало бы невозможным для компилятора, обрабатывающего foo, узнать, может ли someOutsideFunction получить доступ к *p, и, таким образом, невозможно узнать, может ли он безопасно применить указанную оптимизацию.

person supercat    schedule 10.03.2017