2016-04-10 3 views
0

Рассмотрите приведенный ниже код.Является ли компилятор C разрешенным для оптимизации доступа к нераспределенной памяти?

int main() 
{ 
    int* p = (int*)0xABCDEFAB; 
    int a; 

    a = *p; 

    /* do something with a */ 

    return 0; 
} 

компилятор Разрешена оптимизировать прочь доступ к ячейке памяти, на который указывает p? Поскольку он не выделяется (поэтому его содержимое не определено), и доступ к памяти не является наблюдаемым поведением программы, он должен быть разрешен, но, с другой стороны, p может указывать на I/O с отображением памяти.

Каков официальный ответ со стандартной точки C?

ПРИМЕЧАНИЕ. Компилятор наверняка не должен оптимизировать доступ, если p был определен как volatile int *, но он не является изменчивым.

+2

В стандарте C нет требований к поведению вашей программы. Вообще. –

+0

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

+0

@ Lashane Не имеет значения, что p не изменчивый? Если ваше утверждение верно, как его обосновать на основе стандарта? – mrn

ответ

3

C11 draft С

целое число может быть преобразовано в любой тип указателя. За исключением, как указано выше, [когда целое число оценивается в 0], результат определяется реализацией, может быть не правильно выровнен, может не указывать на объект ссылочного типа и может быть ловушкой.

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


Если для реализации 0xabcdef оказался выровненным, ссылки было бы неопределенное поведение (и компилятор может опускает груз).

Если 0xabcdef выравнивается, указатель p не может указывать на адрес 0xabcdef или объект типа int, ссылаясь было бы конкретной реализации .
Компилятор не может напрямую опустить нагрузку в этом случае, но поскольку общее поведение является специфичным для реализации, конечный результат может быть тривиальным и оптимизируемым.

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

Для предотвращения этого последнего случая вам необходимо использовать volatile.


Короче говоря, ваш случай не полностью покрыт стандартом.
Однако есть примечание чтения

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

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


Цитирование:
Если недопустимое значение присваивается указателю, поведение унарного оператора * является неопределенным.

Цитирование из приложения J, реализации конкретного поведения, перечень реализации конкретных аспектов:
- Результат преобразования указателя на целое число, или наоборот.
- Число, порядок и кодирование байтов в любом объекте

+0

Спасибо за то, что он обратил внимание на проблему преобразования, поскольку основное внимание в вопросе было в том, что компилятор может опустить нагрузку, независимо от того, какой адрес удерживает указатель. Насколько я понимаю, ваш ответ НЕТ, даже если p не изменчив, правильно? – mrn

+0

@mrn ... mmm, я бы скорее сказал ДА. Из-за преобразования целочисленного указателя вы можете иметь неопределенное или конкретное поведение. В первом случае ответ ДА. В последнем ответе ДА, если вы не используете 'volatile', NO иначе. –

Смежные вопросы