Функция C возвращает константный указатель, присвоенный неконстантному указателю - предупреждение, а не ошибка

#include <stdio.h>
#include <stdlib.h>

const int * func()
{
    int * i = malloc(sizeof(int));
    (*i) = 5;    // initialize the value of the memory area
    return i;
}

int main()
{
    int * p = func();
    printf("%d\n", (*p));
    (*p) = 3;       // attempt to change the memory area - compiles fine
    printf("%d\n", (*p));
    free(p);
    return 0;
}

Почему компилятор позволяет мне изменять (*p), даже если func() возвращает константный указатель?

Я использую gcc, он показывает только предупреждение в строке int * p = func();: «предупреждение: инициализация отбрасывает квалификаторы из целевого типа указателя».

Спасибо.


person printfede    schedule 24.07.2011    source источник
comment
Есть способ заставить компилятор показывать ошибку вместо этого предупреждения?   -  person printfede    schedule 24.07.2011
comment
@prinfede: -pedantic-errors или -Werror.   -  person Steve Jessop    schedule 24.07.2011
comment
OP вернул не константный указатель, а указатель на константный (или доступный только для чтения) объект.   -  person Cedric Sun    schedule 17.08.2017


Ответы (4)


Ваша программа недействительна. C запрещает неявно удалять такой const, и в соответствии со спецификацией GCC должен выдавать вам как минимум предупреждение для этого кода. Для удаления const.

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

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

person Johannes Schaub - litb    schedule 24.07.2011

Компилятор и язык C «позволяют» вам делать всевозможные глупости, особенно если вы игнорируете предупреждения. Преобразование const int* в int* - единственная точка, в которой компилятор может обнаружить, что здесь что-то не так, и выдает предупреждение для этого преобразования. Это ровно столько неодобрения, сколько вы получите, и поэтому вам не следует игнорировать предупреждения.

Поскольку поведение этой программы определено (GCC, чтобы быть таким же, как если бы вы явно привели к const int*), по крайней мере возможно, что то, что вы сделали, действительно является тем, что вы намеревались сделать. Вот почему код принят.

person Steve Jessop    schedule 24.07.2011

Вы превращаете указатель const в обычный указатель, что, по сути, позволит вам изменить указатель. Вы нарушаете заключенный вами «контракт», возвращая постоянный указатель, но поскольку C - язык со слабой типизацией, он синтаксически законен.

В основном GCC вам здесь помогает. Синтаксически можно превратить указатель const в обычный, но есть вероятность, что вы не захотели этого делать, поэтому GCC выдает предупреждение.

Прочтите дизайн по контракту.

person orlp    schedule 24.07.2011

Во-первых, память действительна в основной, потому что она хранится в куче и не была уничтожена / освобождена. Так что компилятор просто пожалуется вам на предупреждение.

Если вы пытаетесь

const int * p = func();

тогда конечно (*p) = 3 будет ошибкой.

person Stan    schedule 24.07.2011