我在c中有以下代码:
LinkedList
MemAllocLinkedList_add(MemAllocLinkedList self, void* data)
{
LinkedList newElement = (LinkedList)
MemoryAllocator_allocate(self->ma, sizeof(struct sLinkedList));
if (newElement == NULL)
return NULL;
newElement->data = data;
newElement->next = NULL;
LinkedList listEnd = LinkedList_getLastElement((LinkedList) self);
listEnd->next = newElement;
return newElement;
}
和
char*
MemoryAllocator_allocate(MemoryAllocator* self, int size)
{
if (((self->currentPtr - self->memoryBlock) + size) <= self->size) {
char* ptr = self->currentPtr;
self->currentPtr += size;
return ptr;
}
else{
printf("MemoryAllocator_allocate: Out of Memory\n");
return NULL;
}
}
是LinkedList指向sLinkedList的指针:
struct sLinkedList {
void* data;
struct sLinkedList* next;
};
和MemAllocLinkedList指向sMemAllocLinkedList的指针:
struct sMemAllocLinkedList {
void* data;
struct sLinkedList* next;
MemoryAllocator* ma;
};
我有一个程序多次调用这个'MemAllocLinkedList_add'函数没有问题,但有一点,在这个函数中,赋值'listEnd-&gt; next = newElement'用las 16切换前16位,所以没有在listEnd-&gt;下一个975912上,我有-467140594,当我稍后尝试访问该列表的最后一个元素时,会导致SISEGEV错误。
如果我编译它并在具有debian(intel 64bits)和raspberry pi(armv6 32位)的虚拟机上运行它,它可以正常工作。但是,当我尝试使用armv5tej的NanosG20时,我会解释这件事。我使用gcc 4.6。
有人知道为什么会这样吗?
感谢。
编辑:
这是LinkedList_getLastElement:
LinkedList
LinkedList_getLastElement(LinkedList list)
{int i=0;
while (list->next != NULL) {
list = list->next; i++;
}
return list;
}
输入MemoryAllocator:
typedef struct {
char* memoryBlock;
char* currentPtr;
int size;
} MemoryAllocator;
此代码来自libiec61850,是针对子电站的标准61850的实现,因此有更多代码无法在此处发布。我只是发布了我收到错误的部分,但就像我说的那样,仅在使用ARMv5的主板上,而不是在VM或Raspberry Pi上。
答案 0 :(得分:3)
你实际上在所有3个平台上都遇到了同样的问题,只是在Intel和ARMv6上你得到了“看似正常工作”的未定义行为形式。
以下是C标准的相关引用(我必须提交的C99的n1256草案中的6.3.2.3):
指向对象或不完整类型的指针可能会转换为指向其他对象的指针 对象或不完整的类型。如果生成的指针未正确对齐 指向类型,行为未定义。
“正确对齐”的概念由平台的ABI定义。在这种情况下,ARM ABI表示thar char
需要1字节对齐,而指针需要4字节对齐。由于struct sLinkedList
由两个指针组成,因此它必须至少与指针一样严格对齐。
现在,由于MemoryAllocator_allocate
每次都将size
的内部空闲指针天真递增,因此不能保证它返回的char *
比1字节对齐更好,从而转换为到struct sLinkedList *
导致3/4可能情况下的未定义行为。由于编译器往往比报复更加务实,而不是nasal demons你得到了未定义的行为“无论硬件对未对齐的加载/存储做什么”解除引用它,这可能是一个对齐错误,返回一些无意义的数据,甚至返回你期望的数据。
解决方案是使MemoryAllocator_allocate
始终向上舍入size
到最大所需对齐的最大倍数 - 对于ARM ABI,这是8个字节,但如果您确定要< em>从不使用任何64位类型(如double
或long long
),你可能可以使用4个字节。