2017-03-27 2 views
1

마이크로 프로세서 stm32f103에서 일부 C 코드를 작성하고 있습니다. 힙에서 메모리를 할당하는 것이 안정적이지 않기 때문에 C 라이브러리 함수 malloc()free() 등을 사용하지 않는 것이 좋습니다. 대신 컴파일 타임에 미리 큰 정적 메모리를 선언하고 메모리를 재 할당하여 내 가상 동적 메모리 할당 목적. 내 새로운 malloc 구현은 내 컴퓨터에서 테스트 할 때 잘 작동하지만 double 데이터 유형에 대해 malloc을 수행하면 stm32에서 충돌합니다.C가 이중 포인터에 값을 할당합니다.

다음은 내 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에서도 작동합니다.

몇 시간 동안 문제가 발생하여 도움을 받으 셨습니다.

+5

'이중'에 대한 정렬 요구 사항이있을 수 있습니다. – Ryan

+0

정렬 요구 사항? 그것은 8 바이트가 double을 저장하기에 충분하지 않다는 것을 의미합니까? –

+2

네, 어쩌면 코드를 해킹하여 모든 주소가 8로 정렬되도록해야합니다. 나는 그것이 충분한 지보기 위해 4 정렬을 시도 할 것이다. 또한'printf'가 충돌을 일으키지 않는지를 확인하기 위해 정적으로 할당 된 double을 출력 해보십시오. –

답변

1

STM32F1의 코어는 Cortex-M3입니다. 이 QA here은 단순한 명령어 인 Cortex-M3에서 정렬되지 않은 단어 액세스가 허용되지만 not all instructions support unaligned access을 지적합니다. 귀하의 경우, C 컴파일러는 정렬되지 않은 주소를 지원하지 않는 명령어를 double과 함께 사용합니다.

공지 사항이

가 기본 정렬 요구와 함께, 모든 유형의 객체에 대한 포인터에 할당하고 액세스하는 데 사용할 수 있도록 인 포인터를 반환 malloc 표준 라이브러리가 "적절하게 정렬
  • 이러한 개체 또는 할당 된 공간에서 이러한 오브젝트의 배열 "포인터가 다른 포인터로 변환 될 수 있지만(C11 7.22.3)

  • , 는"경우, 생성 포인터 올바르게 대해 정렬되지 참조 된 유형, 동작이 정의되지 않음 "(C11 6.3.2.3p7).

따라서 프로그램 동작이 리턴 된 포인터가 적절 각각 intdouble 대한 정렬되지 않은 경우 이들 라인
int *hoho = mem_malloc(sizeof(int)); 
double *hoho = mem_malloc(sizeof(double)); 

이미 정의되지 않는다.

코드를 수정하려면 항상 올바른 맞춤 포인터를 반환하도록 코드를 수정하십시오. 공식 ARM 컴파일러 maintain an 8-byte aligned heap.

관련 문제