64位机器上的strtok函数

8
以下代码在64位和32位上的工作方式不同,这使得我移植代码时遇到了麻烦。
char * tmp = "How are you?";
printf("size of char * = %ld and size of strtok return val = %ld \n",sizeof(char *),sizeof(strtok(tmp," ")));

以下是输出结果:
32 bit: 
size of char * = 4 and size of strtok return val = 4 

64 bit:

size of char * = 8 and size of strtok return val = 4

strtok的手册说:

   #include <string.h>

   char *strtok(char *str, const char *delim);

RETURN VALUE
       The strtok() and strtok_r() functions return a pointer to the next token, or NULL if there are no more tokens.

在64位机器上,char*应该打印为8个字节。那么为什么在64位机器上,strtok返回一个4个字节的char指针呢?谢谢。

2
你使用哪个编译器得到这些结果的? - Joel
5
你是否忘记了包含 <string.h> 库?那么编译器可能会感到有些传统,对于它不知道的函数假定返回类型为 int - Daniel Fischer
2
已在gcc-4.5.real (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 上确认。太疯狂了。 - sarnold
1
@Daniel:太棒了!就是这样。 - sarnold
无法重现,gcc-4.5.1在使用<string.h>时都显示为8,在没有使用时分别为8和4。 - Daniel Fischer
显示剩余2条评论
2个回答

11
你忘记了 #include <string.h>
这会导致编译器推断出默认的返回类型为 int。通过包含正确的头文件,正确的原型将被引入作用域。
在gcc上,这解决了我的问题。 如果在您的编译器上没有解决问题,请问您使用哪个编译器?

1
你的编译器应该至少在尝试调用未声明的函数时发出警告。如果没有,请查找如何增加其警告级别。(隐式int规则已经在1999年的ISO C标准中被删除)。并且在注释中,原帖作者说他已经包含了string.h;如果是这样的话,那不是问题。 - Keith Thompson
抱歉给您带来了麻烦。我在文件层次结构中有一个string.h的副本。我删除了string.h并让gcc采用默认路径。现在它可以正常工作了。@Daniel,Clark: 感谢您的提示!! - ntalli
@ntalli:include指令应该是#include <string.h>,而不是#include "string.h";这样可以避免从您自己的文件层次结构中获取string.h头文件。并且您绝对应该修复printf格式字符串,就像我在我的答案中描述的那样。使用gcc -std=c99 -pedantic -Wall -Wextra进行编译以获得更好的警告。(如果您想要C89/C90代码而不是C99,请将-std=c99替换为-ansi。) - Keith Thompson
我以后一定会记得添加-std=c99或-ansi。虽然我测试了Keith在这里的第一个评论。我完全从代码中删除了#include<string.h>并重新编译它。它编译成功了!编译器没有报告strtok未定义、未声明的函数。你有什么想法为什么会发生这种情况吗? - ntalli

3
调用strtok(tmp, " ")将导致未定义的行为,因为它会尝试修改tmp指向的字符串常量--但由于sizeof操作数不被评估(有一个不适用于此处的例外),所以这不是问题。
真正的问题在于您尝试使用"%ld"格式打印size_t值,这需要一个unsigned long参数。
如果您的实现支持,size_t参数的正确格式是"%zu"(在C99中添加)。
printf("size of char * = %zu and size of strtok return val = %zu\n",
       sizeof(char *), sizeof(strtok(tmp," ")));

否则,将参数显式转换为适当的大小。我会使用"%lu",因为size_t是一种无符号类型。
printf("size of char * = %lu and size of strtok return val = %lu\n",
       (unsigned long)sizeof(char *), (unsigned long)sizeof(strtok(tmp," ")));

以下是一个完整的自包含程序,应该在任何符合 C89 或更高标准的实现上产生预期结果:
#include <stdio.h>
#include <string.h>
int main(void) {
    char * tmp = "How are you?";
    printf("size of char * = %lu and size of strtok return val = %lu\n",
           (unsigned long)sizeof(char *),
           (unsigned long)sizeof(strtok(tmp," ")));
    return 0;
}

编辑: 根据其他答案中 OP 的评论,似乎 string.h 头文件是问题所在。显然,他遇到了

#include "string.h"

相比于
#include <string.h>

我将在此留下我的答案,因为它描述了需要在OP的代码中修复的另一个问题,尽管不是导致观察到的症状的原因。 而编译器选择了错误的string.h头文件。


我无法相信一个错误的格式说明符会导致一个值为8的64位整数被打印成4,尽管期望和传递的类型都是64位整数。 - Daniel Fischer
@sarnold 可变长度数组? - Daniel Fischer
@DanielFischer:printf格式肯定是一个需要修复的问题。我理解你的观点,它不太可能引起OP提到的特定症状——但OP在评论中说他确实包含了string.h(虽然他没有说<string.h>,但是...)。如果他在程序中添加#include <string.h>,我想看看他得到什么结果。说到这个,我想看看他整个程序而不是他向我们展示的片段。 - Keith Thompson
我在项目中有很多文件,并修改了LD_LIBRARY_PATH以包含我的项目层次结构。不小心,当我将项目复制到64位机器时,我忽略了旧的杂散文件。所以基本上,我确实做了一个#include<string.h>,它从LD_LIBRARY_PATH而不是gcc默认路径中获取。也许这更好地解释了情况。这里的代码片段不是我的项目的一部分。这纯粹是为了调试出了什么问题,当我发现strtok的返回大小只有4个字节时,我感到非常兴奋! - ntalli
$LD_LIBRARY_PATH 影响动态加载器/链接器,但不影响编译器处理 #include 指令。你是否设置了 $CPATH$C_INCLUDE_PATH - Keith Thompson
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接