【问题标题】:How is the linking done for string functions in C?C 中的字符串函数如何链接?
【发布时间】:2017-08-23 20:35:48
【问题描述】:

我尝试使用 sting.h 头文件(不包括它)strlen()strtok() 中的两个不同函数。 strlen 成功执行,没有任何错误(但有一些警告),strtok 在运行时失败。如果我不包含头文件,为什么 strlen() 函数可以工作而不是 strtok() ?我想链接过程中有些东西我不明白。请澄清这种行为。但是,如果我将 a 打印为 '%c' 而不是 '%s' (strtok 返回垃圾值),程序将成功终止。

代码:

int main()
{
    char string[] = "This is a String";
    printf("\nLength of sting is %d\n",strlen(string));
}

警告: hello.c:在函数“main”中: hello.c:4:2:警告:内置函数“printf”的隐式声明不兼容 [默认启用] hello.c:4:37:警告:内置函数‘strlen’的隐式声明不兼容 [默认启用] hello.c:4:2:警告:格式“%d”需要“int”类型的参数,但参数 2 的类型为“long unsigned int”[-Wformat]

输出: $ ./a.out

Length of sting is 16

代码:

int main()
{
    char string[] = "This is a String";
    printf("\nLength of sting is %d\n",strlen(string));
    char *a = strtok(string," ");
    printf("%s",a);
}

警告: $ gcc 你好.c hello.c:在函数“main”中: hello.c:4:2:警告:内置函数“printf”的隐式声明不兼容 [默认启用] hello.c:4:37:警告:内置函数‘strlen’的隐式声明不兼容 [默认启用] hello.c:4:2:警告:格式“%d”需要“int”类型的参数,但参数 2 的类型为“long unsigned int”[-Wformat] hello.c:5:12: 警告:初始化使指针从整数而不进行强制转换[默认启用]

输出: $ ./a.out

Length of sting is 16
Segmentation fault (core dumped)

【问题讨论】:

  • 如果您可以执行您的程序,则链接过程成功。
  • 如果这是真的,那么 strtok() 函数的实现中有些东西我不明白。如果 string.h 不包括在内,它会返回一个垃圾字符,而 strlen() 可以正常工作。但是,如果我包含头文件 strtok() 也可以按预期工作。

标签: c gcc


【解决方案1】:

对于大多数 C 标准库,链接是隐式完成的。您只需要包含您使用的标题(即警告)。

如果您不这样做,您的编译器(将您的代码编译为 ANSI C)假定函数返回 int,而不是它们记录的返回类型。因此,您的程序具有未定义的行为。 始终注意警告!
您必须包含标题 string.hstdio.h

第一个程序可以工作,因为你很幸运,strlen 应该返回一个整数(准确地说是 size_t,但它在你的系统上显示整数的值表示,size_t 让程序滑过)。

第二个失败,因为strtok 返回一个char*,但由于缺少包含指令,它假定为intintchar* 不是兼容的类型,所以你得到的“指针”是无效的。

【讨论】:

  • 晶莹剔透!谢谢!
  • 出于好奇,我们可以安全地使用返回 int 的函数而不包括头文件,即使有警告。
  • @PratyushRaizada - 如果您希望您的代码编译为现代 C(C99 或 C2011 标准),则不是。隐式 int 规则被废除,缺少原型是一个硬错误。一般来说,完全无警告构建也是一个好政策。编译器会发出警告以帮助您。
【解决方案2】:

Sting 是歌手,而不是 C 头文件...不过,问题在于,在 C 中,当您使用未声明的函数时,编译器会猜测它们具有您首先传递给它们的参数的类型,并且返回一个int

这就是您收到所有这些警告的原因:您使用的几个未声明的函数实际上并没有推断出的签名(尽管它们并没有错误,并且最终可以工作),而真正的strtok 返回一个指针,而不是 int (事实上的警告表明您正在将 int 分配给没有强制转换的指针)。您遇到的崩溃很可能是由于原始指针是 64 位的,但在被分配给 a 之前被错误地认为是 int 时被截断为 32 位。

不过,要带回家的一点是:包含标头并且永远不要依赖隐式函数声明。这是一个危险的混乱,仅出于向后兼容性的原因而存在。

【讨论】:

  • 这让人不解为什么编译器会选择为“隐式函数声明”而不是错误抛出警告??
  • @Jay - 将代码编译为 C90,它是有效的,尽管不鼓励。从 C99 开始,隐式 int 规则被废除。
  • @StoryTeller,感谢您的信息。 :)
猜你喜欢
  • 2022-06-19
  • 1970-01-01
  • 2018-05-28
  • 1970-01-01
  • 2017-10-20
  • 2013-06-21
  • 2012-07-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多