2015-09-22 1 views
1

Допускается ли в стандарте C изменять функцию int, указанную как const int *, используя псевдоним int *? Иными словами, следующий код гарантированно всегда возвращает 42 и 1 в стандартном C?C - Изменить константу с помощью псевдонимов-указателей с псевдонимом

#include <stdio.h> 

void foo(const int *a, int *b) 
{ 
    printf("%d\n", *a); 
    *b = 1; 
    printf("%d\n", *a); 
} 

int main(void) 
{ 
    int a = 42; 
    foo(&a, &a); 
    return 0; 
} 

ответ

5

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

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

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

+0

@this fyi не уверен, почему ваш ответ получил downvoted –

+0

Потому что некоторые голоса основаны на статусе других ответов вместо их знаний. «Логика» звучит так: так как был еще один ответ с отрицательным ответом, говорящий «да», поэтому мой ответ также должен быть неправильным. Еще одно объяснение состоит в том, что кто-то просто ошибается и просто очень ревностный избиратель. – this

+0

Парень, задающий вопрос, опустил 3 очка с тех пор, как спросил его, поэтому я думаю, что они занижены, если вы потеряете 1 очко за клик. –

0

Да, вы можете это сделать (если вы знаете, что можете уйти от него).

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

В основном этого не делают.

Есть и другие проблемы с вашим примером, которые, вероятно, не делают его лучшей демонстрацией. Например, для перезагрузки * a во втором printf компилятор может оптимизировать его! (он знает, что «а» не изменился, он знает, что «а» указывает на константу, поэтому ему не нужно перезагружать память, предварительно формируя нагрузку на память для выражения «2 *», она может повторно использовать значение, которое, вероятно, имеет в регистре с 1-го раза загружен «* a»). Теперь, если вы добавите барьер памяти между ними, ваш пример будет работать лучше.

https://en.wikipedia.org/wiki/Memory_barrier GCC? asm volatile (""::: "memory"); // может работать до 2-го отпечатка

Но главный вопрос, который вы задали, да, вы можете это сделать, если знаете, что делаете в других вещах.

+0

Любой компилятор, оптимизирующий перезагрузку, для второго printf принадлежит в trashcan. Никакой барьер не требуется. * тогда ваш пример имеет шанс работать лучше. * Все, что я могу сказать: ??? – this

+0

Просьба указать спецификацию, запрещающую такую ​​оптимизацию. –

+1

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

1

Да и да. Ваша программа определена.

Тот факт, что вы указываете на неконстантную переменную int с указателем на константу int, не делает эту переменную const и может быть до сих пор модифицирован через указатель на int или с использованием метки исходной переменной.

-1

Да, он гарантированно всегда печати 42 и 1.

const int *a означает, что значение указывает на постоянный для указателя a.

Попробуйте разыскивать из-под стражи a (*a = 10;), и вы получите сообщение об ошибке.

Указатель a однако не является постоянным. Например, вы можете сделать a = b.

b может указывать на тот же адрес, что и a, и/или изменять значение, как в вашем примере. Вы указали бы, что значение указателя b будет постоянным (const int *b), вы получите сообщение об ошибке.

Я пытаюсь запомнить, как это:

const int *a - это указывает на объект типа INT, которым не разрешено изменять (любой другой указатель на этот объект может делать то, что он хочет, зависит от его декларации /определение).

+0

Вы даете правильный ответ, но ваше объяснение использует неправильные термины. (Я не спускал вниз) – this

+0

Не беспокойтесь о нижнем. Это так. Меня интересуют, какие условия вы имеете в виду, не в порядке? – Elyasin

+1

константа! = Const. – this

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