string.h包含对代码的影响

时间:2013-12-27 18:06:31

标签: c string

我的示例代码取自Split string with delimiters in C

我发现如果我注释掉#include <string.h>程序,那么当我尝试运行它时会崩溃。为什么会崩溃?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

char** str_split(char* a_str, const char a_delim)
{
    char** result    = 0;
    size_t count     = 0;
    char* tmp        = a_str;
    char* last_comma = 0;
    char delim[2];
    delim[0] = a_delim;
    delim[1] = 0;

    /* Count how many elements will be extracted. */
    while (*tmp)
    {
        if (a_delim == *tmp)
        {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }

    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);

    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;

    result = malloc(sizeof(char*) * count);

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, delim);

        while (token)
        {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, delim);
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }

    return result;
}

int main()
{
    char months[] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
    char** tokens;

    printf("months=[%s]\n\n", months);

    tokens = str_split(months, ',');

    if (tokens)
    {
        int i;
        for (i = 0; *(tokens + i); i++)
        {
            printf("month=[%s]\n", *(tokens + i));
            free(*(tokens + i));
        }
        printf("\n");
        free(tokens);
    }

    return 0;
}

2 个答案:

答案 0 :(得分:2)

如果代码不包含<string.h>,则<string.h>中原型化的程序使用的所有函数的返回类型将被假定为int,即32位。

如果在64位系统上,这使得函数返回指针(64位)很可能会失败。这通常是strdup()的情况,它只返回引用内存的64位地址的32位来保存重复的“字符串”。

我明确暗示上述情况会是这样的警告

warning: implicit declaration of function ‘strdup’

C编译器发出的警告意味着它是一个警告。这样对待它。

答案 1 :(得分:0)

<string.h>标头包含C标准指定的标准字符串函数的声明(可能,根据您的设置,还有一些其他非标准函数,如strdup(),由POSIX定义但不是由C)。

从1990 ISO C标准开始,允许调用没有可见声明的函数,但编译器会对如何定义该函数做出某些假设;特别是,它会假设它返回int个结果。如果它实际上没有这样定义,则调用具有未定义的行为。在某些系统上,调用一个返回char* 的函数,就像它返回一个int一样,显示工作;在其他方面,它可能以各种可怕的方式失败(这实际上更好,因为它使查找和纠正错误更容易)。

一种可能的情况是类型intchar*具有不同的大小(例如,它们在64位系统上通常分别为32位和64位)。或者它们可能具有相同的大小,但可以从不同寄存器中的函数返回。

从1999年标准开始,调用没有可见声明的函数是非法的(约束违反); “隐式int”规则被删除。

这意味着任何符合C99或更高版本标准的编译器必须发出诊断消息。在某些情况下,该诊断可能是一个警告,然后编译器可以继续根据C90规则编译您的程序 - 或者根据编译器开发人员碰巧选择的任何规则。

如果你没有(直接或间接地)包含strlen(),你的编译器至少不会警告你对<stdio.h>的调用,你应该使用编译器支持的任何选项来增加它警告级别。

在某些情况下,您可以忽略警告,但最安全的做法是将编译器警告视为致命错误。