1

我有一个功能:

uint8_t*  createTestBuffer()
{

    uint8_t buffer[] = {5,7,3,4,1,9,3};
    return &buffer;
}

运行它:

uint8_t *buff = createTestBuffer();

返回编译器错误:

c_programming.c:11:9: warning: incompatible pointer types returning 'uint8_t (*)[7]' from a function with result type
      'uint8_t *' (aka 'unsigned char *') [-Wincompatible-pointer-types]
        return &buffer;

我从我的函数返回一个指向 uint8_t 数组的指针。那么我在这里做错了什么?

4

3 回答 3

8

编译器告诉你return &buffer;返回一个指向 7 数组的指针uint8_t(拼写为uint8_t (*)[7]),但你说函数返回uint8_t *,这些是不同且不兼容的指针类型。

如果您编写了return buffer;,则类型将是正确的,但代码仍然是错误的。您不能安全地返回指向堆栈上的本地数组的指针。

要么制作它static const uint8_t buffer[] = { … };并将函数返回类型更改为const uint8_t *,然后相应地使用(这是线程安全的,因为数据永远不会改变):

const uint8_t *createTestBuffer(void)
{
    static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
    return buffer;
}

或者以某种形式使用动态分配:

uint8_t *createTestBuffer(void)
{
    static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
    uint8_t *rv = malloc(sizeof(buffer));
    if (rv != 0)
        memmove(rv, buffer, sizeof(buffer));
    return rv;
}

请注意,这里的调用代码需要检查它是否再次返回一个非空指针,并且它还必须确保它调用free()返回的指针,除非它为空(当调用free()变为可选时)。

或者让调用者传递缓冲区——假设用户知道传递足够的空间,从而过着危险的生活:

void createTestBuffer(uint8_t *output)
{
    static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
    memmove(output, buffer, sizeof(buffer));
}

或者生活不那么危险:

static inline size_t min(size_t a, size_t b) { return (a < b) ? a : b; }

void createTestBuffer(uint8_t *output, size_t outlen)
{
    static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
    memmove(output, buffer, min(sizeof(buffer), outlen));
}

还有其他方法可以处理“输出缓冲区小于复制缓冲区”;此代码尽可能安全地复制,但您可以返回 0 或 1 状态指示截断,或断言提供的长度不小于所需长度,或者……</p>

于 2014-05-11T20:24:02.477 回答
1

这里有两个错误:

您的第一个错误是您使用&运算符(又名地址 of)返回缓冲区,该运算符提供指向变量地址的指针。正如错误告诉你的那样,你的数组已经uint8_t*是你正在返回的。uint8_t(*)[7]并且编译器脾气暴躁,因为你试图返回那个,而你的函数应该返回前者。

但要知道实际上你的代码中存在一个更重要的错误,正如@TimCooper 首次发现的那样:

您在函数范围内分配变量,并希望在该函数之外使用它。在 C 中,当您在函数中声明变量时,用于分配它的内存在该函数退出时被释放,因此即使您更正了函数的类型,也不会按预期工作。

您需要在函数之外声明 uint8_t 数组,并将其作为参数传递给函数:

uint8_t* createTestBuffer(uint8_t* array) {
    array[0] = 5;
    array[1] = 7;
    array[2] = 3;
    array[3] = 4;
    array[4] = 1;
    array[5] = 9;
    array[6] = 3;
    return array;
}

或者您需要使用 malloc 在堆中分配内存而不是在堆栈中分配它:

uint8_t* createTestBuffer() {
    uint8_t* array = , malloc(sizeof(uint8_t)*7);
    array[0] = 5;
    array[1] = 7;
    array[2] = 3;
    array[3] = 4;
    array[4] = 1;
    array[5] = 9;
    array[6] = 3;
    return array;
}

但是free()一旦你完成使用它,你就必须不要忘记缓冲区变量。

于 2014-05-11T20:22:19.537 回答
-1

您会收到警告,因为buffer它是 type uint8_t*。该语句&buffer是类型uint8_t**- 指向指针的指针。

在 C 和 C++ 中,数组名称与指针相同。

char s[4] = { 'a', 'b', 'c', '\0' };
char *p = &s[0];
printf("%s", s);
printf("%s", p);

第二件事是您返回一个指向在堆栈上创建的数组的指针。该数组在函数退出后无效。在实践中,您返回的是一个悬空指针。

如果你想返回一个指针,你应该在堆上分配内存,使用malloc()

uint8_t* createTestBuffer()
{
    uint8_t *buffer = (char*)malloc( 3 * sizeof(char) );
    buffer[0] = 10;
    buffer[1] = 20;
    buffer[2] = 30;
    return buffer;
}

但是还有另一个问题。您正在返回一个指向内存块的指针,但您不知道缓冲区有多大。您可以通过以下方式修改函数以“返回” 2 个值:

void createTestBuffer(uint8_t **buffer, size_t *size)
{
    *buffer = (char*)malloc( 3 * sizeof(char) );
    buffer[0] = 10;
    buffer[1] = 20;
    buffer[2] = 30;
    *size = 3;
}

并这样称呼它:

char *buf;
size_t size;
createTestBuffer(&buf, &size);

享受!

于 2014-05-11T20:21:19.670 回答