【问题标题】:why does wcslen count 1 extra character on argv[1]?为什么 wcslen 在 argv[1] 上计算 1 个额外字符?
【发布时间】:2013-01-02 20:26:31
【问题描述】:

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 编译。

为什么会这样?

【问题讨论】:

  • 我很确定 main only 获取 ASCII(非宽)字符 .. 或者,至少这是我见过的唯一方式。
  • 所以指定 wchar_t 作为参数类型没用?
  • 也许有编译器开关可以使用?
  • 好吧,首先,找到一个确实使用宽字符 argv 的资源(教程、程序、参考)——它有什么作用/需要什么? (看起来它取决于编译器,也请参阅wmain:不确定它是在哪里定义的,但它确实出现在 MSVC++ 文档中。)
  • wWinmain, Unicode, and Mingw 的可能重复项

标签: c++ c gcc mingw32 widechar


【解决方案1】:

main 需要 intchar** 类型的参数(或 char*[] 等价的)。还有一个可选的第三个参数,即环境字符串数组。

但是发生的情况是,大多数编译器都对main 的参数类型安全感到放松。它很高兴地让您声明 main 为 argc 和 argv 采用您想要的任何类型的参数(或无参数)。我认为这在很大程度上是历史性的,向后兼容C 来做到这一点。由于将 char*[] 类型隐式转换为wchar_t*[],字符串会以完全不同的方式进行解释。

因此,正确地说您从 wcslen 获得了预期的 +1 是不正确的。这是技术上未定义的行为。

两个可能的修复:

简单的解决方法就是将第二个参数改为 char 字符串数组,而不是 wchar_t 字符串。

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

如果您的编译器是 Visual Studio,并且您希望传递 Unicode 参数,则解决方法是将程序的入口点声明为 wmain 而不是 main

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

上面的wmain 修复肯定会用mingw 编译,但我不确定链接器是否支持启用wmain 作为程序入口点。试一试就知道了。

【讨论】:

  • 翻译阶段 7 之后没有隐式转换。
【解决方案2】:

这是 C 标准草案的引述,n1570.pdf:

5.1.2.2.1 程序启动

1 程序启动时调用的函数名为main。实现没有声明这个函数的原型。它应定义为返回类型为 int 且不带参数:

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

或带有两个参数(此处称为 argc 和 argv,尽管可以使用任何名称,因为它们是声明它们的函数的局部变量):

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

或等效;10) 或以其他一些实现定义的方式。

10) 因此,int 可以替换为定义为 int 的 typedef 名称,或者 argv 的类型可以写为 char ** argv,依此类推。

这应该很容易理解。如果您的实现支持argv 类型为wchar_t**,那么它将以实现定义的方式在您的实现上工作。如果您需要可移植性,请不要依赖任何实现定义的内容。

此外,wcslen() 被声明为返回一个 size_t 值,您应该将其与%zu 指令一起使用来打印,#include &lt;wchar.h&gt; 可能也是一个好主意。

我认为这些都不会导致您的问题,但它们都会导致未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 2017-11-26
    • 1970-01-01
    • 2016-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多