Функция C возвращает константный указатель, который назначен неконстантному указателю - предупреждение, а не ошибка - PullRequest
1 голос
/ 24 июля 2011
#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() возвращает указатель const?

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

Спасибо.

Ответы [ 4 ]

4 голосов
/ 24 июля 2011

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

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

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

3 голосов
/ 24 июля 2011

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

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

1 голос
/ 24 июля 2011

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

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

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

0 голосов
/ 24 июля 2011

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

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

const int * p = func();

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

...