C 为双指针赋值
C assign value to double pointer
我正在 stm32f103 微处理器上编写一些 C 代码。由于从堆中分配内存不稳定,因此不鼓励我使用 C 库函数 malloc()
和 free()
等。相反,我想到在编译期间提前声明一大块静态内存时间,并重新分配内存以满足我的伪动态内存分配目的。我的新 malloc 实现在我的计算机上测试时工作正常,但是当我为双数据类型执行 malloc 时在 stm32 上崩溃。
这是我的 malloc 实现。我知道这不是真正的动态内存分配,但我这样做只是为了练习使用指针。
pk_malloc.c
#include "pk_malloc.h"
char pool[RESERVE];
void* alloc[RESERVE];
void mem_init()
{
for (int i = 0; i != RESERVE; i++)
{
alloc[i] = NULL;
}
}
void* mem_malloc(size_t size)
{
if (size > 0)
{
for (int i = 0; i != RESERVE; i++)
{
if (alloc[i] == NULL)
{
int end;
for (end = i; end != RESERVE; end++)
{
if (alloc[end] != NULL || end - i == size + 1)
{
break;
}
}
if (end - i == size + 1)
{
for (int k = i + 1; k != end; k++)
{
alloc[k] = &pool[k];
}
return alloc[i + 1];
}
}
}
}
return NULL;
}
void* mem_realloc(void* mem, size_t new_size)
{
if (mem == NULL)
{
return mem_malloc(new_size);
}
int old_size = 0;
void** alloc_t = &alloc[(char*)(mem) - pool];
while (*alloc_t != NULL)
{
old_size++;
alloc_t++;
}
if (new_size <= old_size)
{
mem_free((char*)mem + new_size);
return mem;
}
else
{
int i = alloc_t - alloc;
int size = new_size - old_size;
int end;
for (end = i; end != RESERVE; end++)
{
if (alloc[end] != NULL || end - i == size + 1)
{
break;
}
}
if (end - i == size + 1)
{
for (int k = i; k != end - 1; k++)
{
alloc[k] = &pool[k];
}
return alloc[i];
}
else
{
void* realloc_t = mem_malloc(new_size);
if (realloc_t == NULL)
{
return mem;
}
else
{
mem_copy(realloc_t, mem);
mem_free(mem);
return realloc_t;
}
}
}
}
void mem_copy(void* dest, void* source)
{
int dest_index = (char*)(dest) - pool;
int source_index = (char*)(source) - pool;
char* writer = (char*)(source);
while (alloc[source_index] != NULL && alloc[dest_index] != NULL)
{
pool[dest_index] = pool[source_index];
dest_index++;
source_index++;
}
}
void mem_free(void* mem)
{
if (mem != NULL)
{
void** alloc_t = &alloc[(char*)(mem) - pool];
while (*alloc_t != NULL)
{
*alloc_t = NULL;
alloc_t++;
}
}
}
pk_malloc.h
#ifndef _PK_MALLOC
#define _PK_MALLOC
#include <stdlib.h>
#define RESERVE 64
void mem_init();
void* mem_malloc(size_t size);
void* mem_realloc(void* mem, size_t new_size);
void mem_copy(void* dest, void* source);
void mem_free(void* mem);
#endif
main.c
int main()
{
mem_init();
int* hoho = (int*)(mem_malloc(sizeof(int)));
*hoho = 123;
printf("%d", *hoho);
mem_free(hoho);
}
代码在我的电脑上可以运行,在STM32上也可以运行。但是,当我将数据类型更改为双精度时:
int main()
{
mem_init();
double* hoho = (double*)(mem_malloc(sizeof(double)));
*hoho = 0.618;
printf("%f", *hoho);
mem_free(hoho);
}
它只在我的电脑上有效,而在STM32上却崩溃了。
我做了一些测试和调试,我发现这条线有效,指针不是 NULL 并且它有一个有效地址。
double* hoho = (double*)(mem_malloc(sizeof(double)));
但是这条线崩溃了。
*hoho = 0.618;
经过更多测试,我发现任何占用超过 4 个字节的数据类型都会以同样的方式崩溃,包括 long long
等
奇怪的是,我做了一些用户定义的结构,其中包含很多int
、float
数据类型等,肯定占用了4个字节以上,代码在STM32上运行良好。
struct ABC
{
int a;
float b;
};
这条线没问题。
struct ABC* hoho = (struct ABC*)(mem_malloc(sizeof(struct ABC)));
可以给变量hoho
赋值,并且可以轻松访问其成员,在我的电脑和STM32上都可以工作。
请注意,所有代码都适用于我的笔记本电脑,大多数数据类型也适用于 STM32。
我被这个问题困扰了几个小时,感谢任何帮助。
STM32F1的核心是Cortex-M3。这个QA here points out that while unaligned word access is allowed by Cortex-M3 for simple instructions, not all instructions support unaligned access。在您的情况下,C 编译器使用不支持双精度未对齐地址的指令。
注意
标准库malloc
returns一个指针"suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated"(C11 7.22.3)
虽然一个指针可以转换为另一个指针,"if the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined" (C11 6.3.2.3p7).
因此程序的行为在这些行中已经未定义
int *hoho = mem_malloc(sizeof(int));
double *hoho = mem_malloc(sizeof(double));
如果返回的指针未分别与 int
和 double
对齐。
要修复代码,请对其进行更改,使其始终 returns 正确对齐的指针。官方 ARM 编译器 maintain an 8-byte aligned heap.
我正在 stm32f103 微处理器上编写一些 C 代码。由于从堆中分配内存不稳定,因此不鼓励我使用 C 库函数 malloc()
和 free()
等。相反,我想到在编译期间提前声明一大块静态内存时间,并重新分配内存以满足我的伪动态内存分配目的。我的新 malloc 实现在我的计算机上测试时工作正常,但是当我为双数据类型执行 malloc 时在 stm32 上崩溃。
这是我的 malloc 实现。我知道这不是真正的动态内存分配,但我这样做只是为了练习使用指针。
pk_malloc.c
#include "pk_malloc.h"
char pool[RESERVE];
void* alloc[RESERVE];
void mem_init()
{
for (int i = 0; i != RESERVE; i++)
{
alloc[i] = NULL;
}
}
void* mem_malloc(size_t size)
{
if (size > 0)
{
for (int i = 0; i != RESERVE; i++)
{
if (alloc[i] == NULL)
{
int end;
for (end = i; end != RESERVE; end++)
{
if (alloc[end] != NULL || end - i == size + 1)
{
break;
}
}
if (end - i == size + 1)
{
for (int k = i + 1; k != end; k++)
{
alloc[k] = &pool[k];
}
return alloc[i + 1];
}
}
}
}
return NULL;
}
void* mem_realloc(void* mem, size_t new_size)
{
if (mem == NULL)
{
return mem_malloc(new_size);
}
int old_size = 0;
void** alloc_t = &alloc[(char*)(mem) - pool];
while (*alloc_t != NULL)
{
old_size++;
alloc_t++;
}
if (new_size <= old_size)
{
mem_free((char*)mem + new_size);
return mem;
}
else
{
int i = alloc_t - alloc;
int size = new_size - old_size;
int end;
for (end = i; end != RESERVE; end++)
{
if (alloc[end] != NULL || end - i == size + 1)
{
break;
}
}
if (end - i == size + 1)
{
for (int k = i; k != end - 1; k++)
{
alloc[k] = &pool[k];
}
return alloc[i];
}
else
{
void* realloc_t = mem_malloc(new_size);
if (realloc_t == NULL)
{
return mem;
}
else
{
mem_copy(realloc_t, mem);
mem_free(mem);
return realloc_t;
}
}
}
}
void mem_copy(void* dest, void* source)
{
int dest_index = (char*)(dest) - pool;
int source_index = (char*)(source) - pool;
char* writer = (char*)(source);
while (alloc[source_index] != NULL && alloc[dest_index] != NULL)
{
pool[dest_index] = pool[source_index];
dest_index++;
source_index++;
}
}
void mem_free(void* mem)
{
if (mem != NULL)
{
void** alloc_t = &alloc[(char*)(mem) - pool];
while (*alloc_t != NULL)
{
*alloc_t = NULL;
alloc_t++;
}
}
}
pk_malloc.h
#ifndef _PK_MALLOC
#define _PK_MALLOC
#include <stdlib.h>
#define RESERVE 64
void mem_init();
void* mem_malloc(size_t size);
void* mem_realloc(void* mem, size_t new_size);
void mem_copy(void* dest, void* source);
void mem_free(void* mem);
#endif
main.c
int main()
{
mem_init();
int* hoho = (int*)(mem_malloc(sizeof(int)));
*hoho = 123;
printf("%d", *hoho);
mem_free(hoho);
}
代码在我的电脑上可以运行,在STM32上也可以运行。但是,当我将数据类型更改为双精度时:
int main()
{
mem_init();
double* hoho = (double*)(mem_malloc(sizeof(double)));
*hoho = 0.618;
printf("%f", *hoho);
mem_free(hoho);
}
它只在我的电脑上有效,而在STM32上却崩溃了。
我做了一些测试和调试,我发现这条线有效,指针不是 NULL 并且它有一个有效地址。
double* hoho = (double*)(mem_malloc(sizeof(double)));
但是这条线崩溃了。
*hoho = 0.618;
经过更多测试,我发现任何占用超过 4 个字节的数据类型都会以同样的方式崩溃,包括 long long
等
奇怪的是,我做了一些用户定义的结构,其中包含很多int
、float
数据类型等,肯定占用了4个字节以上,代码在STM32上运行良好。
struct ABC
{
int a;
float b;
};
这条线没问题。
struct ABC* hoho = (struct ABC*)(mem_malloc(sizeof(struct ABC)));
可以给变量hoho
赋值,并且可以轻松访问其成员,在我的电脑和STM32上都可以工作。
请注意,所有代码都适用于我的笔记本电脑,大多数数据类型也适用于 STM32。
我被这个问题困扰了几个小时,感谢任何帮助。
STM32F1的核心是Cortex-M3。这个QA here points out that while unaligned word access is allowed by Cortex-M3 for simple instructions, not all instructions support unaligned access。在您的情况下,C 编译器使用不支持双精度未对齐地址的指令。
注意
标准库
malloc
returns一个指针"suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated"(C11 7.22.3)虽然一个指针可以转换为另一个指针,"if the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined" (C11 6.3.2.3p7).
因此程序的行为在这些行中已经未定义
int *hoho = mem_malloc(sizeof(int));
double *hoho = mem_malloc(sizeof(double));
如果返回的指针未分别与 int
和 double
对齐。
要修复代码,请对其进行更改,使其始终 returns 正确对齐的指针。官方 ARM 编译器 maintain an 8-byte aligned heap.