Я получаю это предупреждение:
note: expected ‘const char **’ but argument is of type ‘char **’
Теперь я передаю аргументы, переведя их в const char **
. Есть ли другой способ избавиться от него?
Я получаю это предупреждение:
note: expected ‘const char **’ but argument is of type ‘char **’
Теперь я передаю аргументы, переведя их в const char **
. Есть ли другой способ избавиться от него?
Короткий ответ
Можете ли вы безопасно отображать char **
до const char**
? Нет. (В любом случае, это безопасно), и причина гораздо более тонкая, чем вы думаете. Можете ли вы избавиться от него по-другому? Конечно. Загрузите массив значений const char*
из ваших значений char*
и передайте их вместо этого. (или изменить прототип вызываемого, но это обманывает = P).
Рассмотрим следующий код, который по существу делает все, что вам нужно, за исключением вызова функции. Отмеченная строка демонстрирует эквивалентную точку трансляции
const char *s = "Test";
char *p = NULL;
char **pp = &p; // Put address of our pointer in our pointer-to-pointer.
const char **cpp = pp; // Here: assigning char** to const char**
*cpp = s; // perfectly legal; pp and s both finish "char const"
*p = 0; // ru ro raggy
Требуется некоторое время, чтобы действительно посмотреть на это, и, по общему признанию, я тоже этого не видел. @sheu проделала прочную работу по поиску около 24 часов, прежде чем я действительно подумал об этом достаточно долго, чтобы понять, что он был прав все время (и я фактически поддержал этот ответ, прежде чем писать этот). Тогда я подумал, что он ошибался в то же время, когда думал, что его ответ не применим. Оказывается, мы оба ошибались в этом прыжке, потому что он был прав в первый раз, я ошибся во второй раз, а теперь... тьфу.
В VS2012 и VS2010 обе отмеченная строка будет отмечать ошибку без трансляции. clang будет скомпилировать его с предупреждением на C, но разрешить его (что мне показалось удивительным). Учитывая, что вам действительно нужно выйти из своего счастливого места, чтобы сломать его, но он по-прежнему не работает.
В остальном это диатриба для определения типов указателей, их константы и того, что эквивалентно тому, что.
Длинная диатриба на указателях и константах
Предупреждение состоит в том, что char **
и const char **
не эквивалентны (duh). Чтобы быть правдой, вы можете исправить прототип (вызываемый) или исправить вызывающего абонента (путем загрузки массива const char *
и передачи этого). Но можете ли вы безопасно прибегать к первому ко второму? Ммм....
Помните, что по стандарту const
он сразу переходит к элементу слева. Объявление его на самом левом из типа данных - это тонкость, которую поддерживает язык, но часто вводит путаницу или проблемы. Как правило, если const
появляется в крайнем левом углу объявления непосредственно перед типом, оно применяется к типу данных; не последующий указатель (если есть). Когда он появляется справа от всего, он применим к части объявления слева-слева, будь то часть типа данных или часть указателя, но независимо от того, что она применима только к одной части.
Далее следует множество примеров:
Без указаний:
const char ch; // const character. must be initialized.
char const ch; // same as above
Single-Косвенность:
char *p; // p is mutable, *p is mutable
const char *p; // p is mutable, *p is const
char const *p; // same as above.
char *const p; // p is const, *p is mutable, must be initialized.
char const *const p; // p is const, *p is const, must be initialized.
Double Indirection:
char **p; // ptr-to-ptr-to-char
// p, *p, and **p are ALL mutable
const char **p; // ptr-to-ptr-to-const-char
// p and *p are mutable, **p is const
char const **p; // same as above
char *const *p; // ptr-to-const-ptr-to-char
// p is mutable, *p is const, **p is mutable.
char **const p; // const-ptr-to-ptr-to-char
// p is const, *p is mutable, **p is mutable.
// must be initialized.
const char **const p; // const-ptr-to-ptr-to-const-char
// p is const, *p is mutable, **p is const.
// must be initialized.
char const **const p; // same as above
char const *const *p; // ptr-to-const-ptr-to-const-char
// p is mutable, *p is const, **p is const.
const char *const *p; // same as above.
char *const *const p; // const-ptr-to-const-ptr-to-char
// p is const, *p is const, **p is mutable.
// must be initialized.
И, конечно, кто может уйти из дома без...
char const *const *const p; // const-ptr-to-const-ptr-to-const-char
// everything is const.
// must be initialized.
const char *const *const p; // same as above
Итак, как это влияет на ваш вопрос? При компиляции этого кода на C без приведения вы получите предупреждение компилятора (или ошибку при компиляции с помощью -Werror
). При компиляции на С++ вы просто ошиблись, потому что подпись параметра не совпадает. Но почему?
Поскольку они не имеют прямой эквивалентности:
const char **p; // ptr-to-ptr-to-const-char
// p and *p are mutable **p is const
char **p; // ptr-to-ptr-to-char
// p, *p, and **p are all mutable
При компиляции с clang точное предупреждение в C указано как:
main.c: 15: 9: Передача
char **
в параметр типаconst char **
отбрасывает квалификаторы во вложенных типах указателей.
VS2010 и VS2012, с другой стороны, бросают ошибку:
ошибка C2440: 'initializing': невозможно преобразовать из 'char **' в 'const char **'
Кажется странным, но VS на самом деле более корректен (чудеса никогда не прекращаются).
И это имеет смысл. Уязвимость в объявлении типа заключается в том, что первая из них не позволяет изменять окончательные данные, вторая делает. Сверху мы знаем, что char **
и const char **
(aka. char const **
) не совпадают. В нижней части одной находится указатель на const char
, а другой - указатель на char
.
edit. Я даже ответил на неправильный вопрос. Мой ответ совершенно не имеет значения! Игнорируйте меня, пожалуйста.
отредактируйте 2: после того, как вопрос с джентльменом задает вопрос, выясняется, что мой ответ действительно имеет значение. C'est la vie.
Это забавный бит C, что имеет смысл, если вы достаточно серьезно думаете об этом.
В основном, преобразование:
char** ptr;
const char** const_ptr;
const_ptr = ptr; // <-- BAD!
не разрешено.
Почему, спросите вы? "Я делаю вещи более const! Это, очевидно, хорошо!"
Хорошо, подумайте об этом. Если это разрешено, то:
const char c = 'A';
char* ptr;
const char** const_ptr = &ptr; // <-- ILLEGAL, but what if this were legal?
*const_ptr = &c;
*ptr = 'B'; // <- you just assigned to "const char c" above.
БАМ, ты мертв. Итак... нет: -)
Предупреждение сообщает вам, что функция, которую вы вызываете, ожидает данный параметр как const char**
, но вы передаете параметр char**
. Чтобы избавиться от этого предупреждения, вы могли
const char**
const char**
(как в настоящее время)char**