Почему wcslen считает 1 дополнительный символ в argv[1]?

argv[1] кажется, возвращает 1 дополнительный символ, чем то, что вводится. argv[2] верно.

#include <stdio.h>
int main(int argc, wchar_t *argv[])
{
  printf("%d %d\n",wcslen(argv[1]),wcslen(argv[2]) );
  return 0;
}

Я использую mingw32 для компиляции. Я собираю с gcc myprog.c,

Почему это так?

3 ответа

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

Но что происходит, так это то, что большинство компиляторов не заботятся о безопасности типов параметров для. Он с радостью позволяет вам объявить, что принимает любой тип аргументов (или не принимает аргументов), который вы хотите для argc и argv. Я думаю, что это в значительной степени историческое с обратной совместимостью с Cсделать это. И в результате неявного приведения char*[] введите в wchar_t*[], строки интерпретируются совершенно по-разному.

Поэтому неверно утверждать, что от wcslen вы получаете +1 больше, чем ожидалось. Это технически неопределенное поведение.

Два возможных исправления:

Простое исправление - это просто этот delcare второй параметр массив char струны вместо wchar_t струны.

      int main(int argc, char* argv[])

Если ваш компилятор был Visual Studio и вы хотели, чтобы аргументы Unicode передавались, исправление заключалось бы в объявлении точки входа вашей программы как вместо main

      int wmain(int argc, wchar_t* argv[])

Вышеупомянутое исправление, безусловно, будет скомпилировано с mingw, но я не уверен, поддерживает ли компоновщик для включения wmainкак точка входа в программу. Попробуйте и узнайте.

Вот цитата из черновика стандарта C, n1570.pdf:

5.1.2.2.1 Запуск программы

1 Функция, вызываемая при запуске программы, называется основной. Реализация не объявляет прототип для этой функции. Он должен быть определен с типом возврата int и без параметров:

int main(void) { /* ... */ }

или с двумя параметрами (именуемыми здесь как argc и argv, хотя могут использоваться любые имена, так как они являются локальными для функции, в которой они объявлены):

int main(int argc, char *argv[]) { /* ... */ }

или эквивалент;10) или каким-либо другим способом, определяемым реализацией.

10) Таким образом, int может быть заменено именем typedef, определенным как int, или тип argv может быть записан как char ** argv, и так далее.

Это должно быть довольно просто для понимания. Если ваша реализация поддерживает argv с типом wchar_t **, то она будет работать с вашей реализацией в зависимости от реализации. Если вам требуется переносимость, не полагайтесь ни на что, определяемое реализацией.

Хорошая ссылка для этого - функция CommandLineToArgvW.

Другие вопросы по тегам