指针差异和size_t

时间:2013-11-25 16:08:39

标签: c casting posix

我想分配内存来保存从给定字符串中提取的字段。字段的大小由两个指针的差异决定,请参见以下最小示例:

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

int
main(int argc, char *argv[])
{
    const char line[] = "foo,bar,baz";
    char *field_start = line;
    char *field_end;
    char *field;

    field_end = strchr(line, ',');
    field = malloc(field_end - field_start + 1);
    memcpy(field, field_start, field_end - field_start);
    *(field + (field_end - field_start)) = '\0';

    printf("field=\"%s\"\n", field);

    /* ... */

    return (0);
}

使用clang -Weverything -o ex ex.c编译此代码会产生以下警告:

ex.c:14:41: warning: implicit conversion changes signedness: 'long' to 'unsigned long'
      [-Wsign-conversion]
        field = malloc(field_end - field_start + 1);
                ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~^~~
ex.c:15:39: warning: implicit conversion changes signedness: 'long' to 'unsigned long'
      [-Wsign-conversion]
        memcpy(field, field_start, field_end - field_start);
        ~~~~~~                     ~~~~~~~~~~^~~~~~~~~~~~~

据我了解,指针差异的结果是ptrdiff_t类型,而malloc / memcpy期望一个类型为size_t的参数。 所以我的问题是如何解决这个问题并消除警告?如 field_end >= field_start区别不能变为负面,所以也可能 以上安全地投放到size_t

    field = malloc(size_t(field_end - field_start + 1));
    memcpy(field, size_t(field_start, field_end - field_start));

或者我正在忽视的任何问题?

注意:

为简单起见,上面没有检查返回值。 field_start和_end当然应该是const。

1 个答案:

答案 0 :(得分:4)

field_end >= field_start仅在strchr不返回NULL的情况下成立,即类型系统中没有任何内容告诉编译器这确实总是成立。因此警告是有道理的。但是,如果您确定不是这种情况,那么(size_t)(field_end - field_start)应该没问题。为了不重复这一点,我添加

size_t field_len;
/* memchr & null-check go here */
field_len = (size_t)(field_end - field_start);

...然后全部使用field_len

话虽如此,您可能希望通过拨打strndup来替换malloc / memcpy组合。