GCC компилятор и преобразование const char * в char * - PullRequest
4 голосов
/ 18 января 2012

Я пытаюсь построить симулятор архитектуры M-SIM, но когда я запускаю утилиту make, gcc сообщает об этой ошибке (это даже не предупреждение)

примечание: ожидается 'char *', но аргумент имеет тип 'const char *'

С тех пор, когда это считается ошибкой. Есть ли флаги, которые могут обойти эту проверку?

Ответы [ 4 ]

9 голосов
/ 18 января 2012

Это ошибка, потому что передача аргумента const char* в функцию, которая принимает параметр char*, нарушает правильность const;это позволило бы вам изменить объект const, который бы победил всю цель const.

Например, эта программа на C:

#include <stdio.h>

void func(char *s) {
    puts(s);
    s[0] = 'J';
}

int main(void) {
    const char message[] = "Hello";
    func(message);
    puts(message);
    return 0;
}

производит следующую командуДиагностика времени из gcc:

c.c: In function ‘main’:
c.c:10:5: warning: passing argument 1 of ‘func’ discards qualifiers from pointer target type
c.c:3:6: note: expected ‘char *’ but argument is of type ‘const char *’

Последнее сообщение помечено как «примечание», потому что оно относится к (совершенно законному) объявлению func(), объясняя, что это объявление параметра, к которому относится предупреждение.

Что касается стандарта C, то это нарушение ограничения, что означает, что компилятор может обработать его как фатальную ошибку.По умолчанию gcc просто предупреждает об этом и выполняет неявное преобразование из const char* в char*.

Когда я запускаю программу, вывод:

Hello
Jello

, который показываетчто, хотя я объявил message как const, функция смогла его изменить.

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

(Передача строкового литерала в func() не вызовет эту диагностику, посколькуC не обрабатывает строковые литералы как const. (Это делает поведение попытки изменить строковый литерал неопределенным.) Это по историческим причинам. У gcc есть опция, -Wwrite-strings, которая заставляет его обрабатывать строкулитералы как const, это на самом деле нарушает стандарт C, но это может быть полезной проверкой.)

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

Я даже сам скачал и собрал симулятор архитектуры M-SIM, но я не увидел этого конкретного сообщения.

4 голосов
/ 18 января 2012

Сначала при вызове функции (функции, определенной с помощью прототипа) аргументы преобразуются в тип параметров, как если бы они были назначены.

Можно присвоить значение типа char * объекту типа const char *, но нельзя присвоить значение const char * объекту char *.

Это ограничение появляется в ограничениях оператора присваивания:

(C99, 6.5.16.1p1) "Должно быть выполнено одно из следующего: [...] - оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов, а тип, указанный слева, имеет все квалификаторы типа, указанного справа; "

Это ограничение разрешает первое назначение, но запрещает второе.

Объявление указателя с типом const char * означает, что вы не будете изменять объект, на который указывает указатель. Таким образом, вы можете присвоить указателю значение типа char *, это просто означает, что объект не будет изменен с помощью указателя const char *.

Но объявление указателя типа char * означает, что вы можете изменить объект, на который указывает указатель. Не имеет смысла присваивать ему значение const char *.

Помните, что в C const не означает константу , а скорее только для чтения . Квалификатор const, помещенный перед типами указателей, означает, что вы обещаете не изменять объекты с помощью объектов этих типов указателей.

3 голосов
/ 18 января 2012

Указатели на const -квалифицированные типы неявно преобразуются в указатели на не const -квалифицированные типы. Необходимо явное преобразование через приведение, например:

foo((char *)bar)
0 голосов
/ 18 января 2012

Выполните следующие действия, если вы этого еще не сделали:

  1. Объявите указатель на символ.
  2. При необходимости выделите место и скопируйте содержимое из константной строки.(например, используя strdup())
  3. И замените указатель на постоянный символ новым указателем на символ.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...