Предупреждение 359 при передаче строки в char*

Я пытаюсь передать строку функции:

void PassString(unsigned char * value)
{
    // ...
}

int main(void)
{
    while(1)
    {
        PassString("TEST");
    }
}

Я получаю предупреждение: (359) недопустимое преобразование между типами указателей.


person ddd    schedule 08.11.2018    source источник
comment
может быть, в вашей среде строковые литералы signed char *?   -  person Sourav Ghosh    schedule 08.11.2018
comment
Также TEST является константой.   -  person Gem Taylor    schedule 08.11.2018
comment
@GemTaylor Верно, но не имеет отношения к рассматриваемому предупреждающему сообщению.   -  person Sourav Ghosh    schedule 08.11.2018
comment
@SouravGhosh На самом деле даже не имеет значения, подписаны ли char, это не так. char [] не может быть автоматически преобразовано ни в signed char*, ни в unsigned char *.   -  person HolyBlackCat    schedule 08.11.2018
comment
@SouravGhosh Хорошо, поэтому преобразование const может генерировать другое предупреждение, но в наши дни достойный компилятор C должен генерировать для него предупреждение или ошибку.   -  person Gem Taylor    schedule 08.11.2018
comment
Строковые литералы @SouravGhosh должны быть char[N]   -  person M.M    schedule 08.11.2018
comment
@ M.M да, сэр, и знак char зависит от реализации, не так ли?   -  person Sourav Ghosh    schedule 08.11.2018
comment
@HolyBlackCat Не автоматически, сэр, простое char подписано или не подписано, зависит от реализации. Я считаю, что для реализации, где простое char равно unsigned, приведенный выше код не должен выдавать никаких предупреждений.   -  person Sourav Ghosh    schedule 08.11.2018
comment
@SouravGhosh да, но это другой тип, чем signed char и unsigned char. Даже если одинаковая подписанность как у того, так и у другого.   -  person M.M    schedule 08.11.2018
comment
@M.M Полностью согласен. Я думаю, что char - единственный случай, когда char и signed char упоминаются как разные типы в стандарте. int, с другой стороны, это signed int - по умолчанию, поэтому они одного типа.   -  person Sourav Ghosh    schedule 08.11.2018
comment
@ Джем Тейлор, твой ответ сработал! const unsigned char * отлично сработал для меня. Отметьте это как ответ.   -  person ddd    schedule 08.11.2018
comment
const unsigned char * просто отключает предупреждение, но не решает основную проблему. Какой компилятор вы используете? GCC дает более конкретное предупреждение: цели указателя различаются по подписанию.   -  person GermanNerd    schedule 08.11.2018
comment
Компилятор Xc8...   -  person ddd    schedule 08.11.2018


Ответы (2)


Короткий ответ:

Строковые литералы, такие как "TEST", имеют тип char[] в C.

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


Некоторая история создания char:

Система типов C немного нефункциональна, когда дело доходит до типов символов. На заре времен, когда динозавры ходили по земле, не было указано, должно ли char быть signed или unsigned по умолчанию.

signed имеет смысл, потому что это делает char совместимым с большими целочисленными типами. unsigned также имело смысл, потому что не существует таблиц символьных символов с отрицательными индексами.

После стандартизации языка уже существовали различные компиляторы, которые давали char разную подпись. Поэтому было решено, что подписанность char должна определяться реализацией. То есть: решает каждый компилятор.

По той же причине типы char, signed char и unsigned char были определены как 3 разных типа. Это означает, что вы не можете неявно преобразовывать указатели на эти типы. Вместо этого вам нужно использовать явное преобразование путем приведения типов.

Только типы персонажей ведут себя так странно. Если взять, например, int и signed int, они всегда совместимы, а int всегда подписано.

Это известный недостаток языка C. Таким образом, типы из библиотеки stdint.h предпочтительнее «сырых» типов символов.


Рекомендации по использованию типов символов:

  • Используйте тип char, если вы имеете дело с текстовыми строками (до 8 бит), и только в этом случае.
  • Используйте тип unsigned char или uint8_t, если вы имеете дело с необработанными двоичными данными или выполняете каламбуры и т. д.
  • Используйте signed char или int8_t, если вы выполняете арифметические операции с 8-битными целыми числами со знаком.
  • Используйте unsigned char или uint8_t, если вы выполняете арифметику 8-битных целых чисел без знака.
  • Никогда не возникает опасности при преобразовании между различными типами символов, если не имеет значения подписанность.
  • Но... будьте осторожны, выполняя какие-либо арифметические действия с этими типами, так как они сопряжены со многими ловушками. См. правила продвижения неявного типа.
person Lundin    schedule 08.11.2018

Передаваемый строковый литерал имеет тип char [], но аргумент задается как unsigned char *.

Поэтому измените тип аргумента на char[].

person Edward Karak    schedule 08.11.2018
comment
«аргумент задан как unsigned char *» должно быть «тип параметра — unsigned char *». Исторически сложилось некоторое смешение этих терминов, но стандарт C определяет параметр как объект, объявленный как часть объявления функции, который получает значение при входе в функцию и аргумент. как выражение в скобках вызова функции. Другими словами, аргумент — это передаваемое выражение, а параметр — контейнер для полученного объекта. - person Eric Postpischil; 08.11.2018
comment
Хотя строковый литерал имеет тип char [], он не передается в функцию. Во-первых, он автоматически преобразуется в char *, поэтому в функцию передается именно char *, а не строковый литерал или char []. - person Eric Postpischil; 08.11.2018