Redefine_fopen_malloc

转载链接,侵删

在我们进行嵌入式开发时,难免要移植一些现有的成熟代码库,这些库大部分要借助C标准库中的输入输出接口、内存分配函数等。这也就产生了库函数重定向的问题。我们最常用重定向库函数为printf函数,重定向的方法为:

AC5:
#ifndef __MICROLIB  //不勾选微库的话需要关闭半主从模式
#pragma import(__use_no_semihosting)
#endif
int fputc(int ch, FILE *f){
  //ch为要发送的字符
  return HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100)==HAL_OK?ch:-1;
}

AC6:
#ifndef __MICROLIB //不勾选微库的话需要关闭半主从模式
__asm(".global __use_no_semihosting\n\t")
#endif
int fputc(int ch, FILE *f){
//ch为要发送的字符
return HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100)==HAL_OK?ch:-1;
}

有时我们需要重定向malloc、free等内存分配函数,不使用C库的内存分配,这在使用rtos时很常见,重定向malloc、free的方法为:

AC5
#pragma import(__use_no_heap_region)  //声明不使用C库的堆

void *malloc (size_t size){
        return OS_Malloc(size);
}

void free(void* p){
        OS_Free(p);
}

void *realloc(void* p,size_t want){
        return OS_Realloc(p,want);
}

void *calloc(size_t nmemb, size_t size){
        return OS_Calloc(nmemb,size);
}

AC6:

__asm(".global __use_no_heap_region\n\t"); //声明不使用C库的堆
void *malloc (size_t size){
        return OS_Malloc(size);
}

void free(void* p){
        OS_Free(p);
}

void *realloc(void* p,size_t want){
        return OS_Realloc(p,want);
}

void *calloc(size_t nmemb, size_t size){
        return OS_Calloc(nmemb,size);
}

有的时候我们需要重定向C库的文件IO,如在移植LUA解释器时,源码中会调用C库的fopen、fread等函数,需要对这些IO重定向,这里以FATFS为例实现重定向。 最后给出AC5与AC6均适用的例子,包含重定向printf、重定向malloc、free、重定向io,这里需要注意的是,一定要将前面的fputc注释掉,因为在编译时fputc的优先级要大于_sys_write,这就导致printf、fwirte都会重定向到fputc中。

#include <rt_sys.h>
#include <stdio.h>

#define SUPPORT_FILE_SYSTEM                0
#define SUPPORT_MALLOC                     1

#include "stm32h7xx_hal.h"
extern UART_HandleTypeDef huart1;

//约定返回值为1函数执行成功,0函数执行失败
#define MESSAGE_PRINT(BUF,LEN)  HAL_UART_Transmit(&huart1, (uint8_t*)BUF,LEN, 100)==HAL_OK
#define MESSAGE_SCANF(BUF,LEN) 0
#define OS_Malloc(SIZE)   NULL
#define OS_Free(P)
#define OS_Calloc(N,SIZE) NULL
#define OS_Realloc(P,SIZE) NULL

#if SUPPORT_FILE_SYSTEM
        #include "ff.h"
#endif

#if defined(__clang__)
        __asm(".global __use_no_semihosting\n\t");
        #if SUPPORT_MALLOC
                __asm(".global __use_no_heap_region\n\t");
        #endif
#elif defined(__CC_ARM)
        #pragma import(__use_no_semihosting)
        #if SUPPORT_MALLOC
                #pragma import(__use_no_heap_region)
        #endif
#endif

#if defined(__MICROLIB)
        #if defined(__clang__)
                __asm(".global __use_full_stdio\n\t");
        #elif defined(__CC_ARM)
                #pragma import(__use_full_stdio)
        #endif
#endif

#define STDIN        0
#define STDOUT        1
#define STDERR        2
#define IS_STD(fn)        ((fn)>=0&&(fn)<=2)
/*
* These names are used during library initialization as the
* file names opened for stdin, stdout, and stderr.
* As we define _sys_open() to always return the same file handle,
* these can be left as their default values.
*/
const char __stdin_name[] = ":tt";
const char __stdout_name[] = ":tt";
const char __stderr_name[] = ":tt";


FILEHANDLE _sys_open(const char *pcFile, int openmode)
{
#if SUPPORT_FILE_SYSTEM
        BYTE mode;
        FIL *fp;
        FRESULT fr;
#endif
        if(pcFile==__stdin_name)
                return STDIN;
        else if(pcFile==__stdout_name)
                return STDOUT;
        else if(pcFile==__stderr_name)
                return STDERR;
#if SUPPORT_FILE_SYSTEM
        fp=malloc(sizeof(FIL));
        if(fp==NULL){
                printf("malloc fail!\r\n");
                return -1;
        }
        /* http://elm-chan.org/fsw/ff/doc/open.html */
        if(openmode & OPEN_W){
                mode = FA_CREATE_ALWAYS | FA_WRITE;
                if (openmode & OPEN_PLUS)
                        mode |= FA_READ;
        }
        else if(openmode & OPEN_A){
                mode = FA_OPEN_APPEND | FA_WRITE;
                if (openmode & OPEN_PLUS)
                        mode |= FA_READ;
        }
        else{
                mode = FA_READ;
                if (openmode & OPEN_PLUS)
                        mode |= FA_WRITE;
        }

        fr = f_open(fp, pcFile, mode);
        if (fr == FR_OK)
                return (FILEHANDLE)fp;

        free(fp);
#endif
        return -1;
}

int _sys_close(FILEHANDLE fh)
{
#if SUPPORT_FILE_SYSTEM
        FRESULT fr;
#endif
        if(IS_STD(fh))
                return 0;
#if SUPPORT_FILE_SYSTEM
        fr = f_close((FIL *)fh);
        if (fr == FR_OK){
                free((void *)fh);
                return 0;
        }
#endif
        return -1;
}

int _sys_write(FILEHANDLE fh, const unsigned char *buf,\
        unsigned len, int mode)
{        
#if SUPPORT_FILE_SYSTEM
        FRESULT fr;
        UINT bw;
#endif
        if(fh==STDIN)
                return -1;
        
        if(fh==STDOUT||fh==STDERR){
                return MESSAGE_PRINT(buf,len)?0:-1;
        }
#if SUPPORT_FILE_SYSTEM        
        fr = f_write((FIL *)fh, buf, len, &bw);
        if (fr == FR_OK)
                return len - bw;
#endif        
        return -1;
}

int _sys_read(FILEHANDLE fh, unsigned char *buf,\
        unsigned len, int mode)
{
#if SUPPORT_FILE_SYSTEM
        FRESULT fr;
        UINT br;
#endif
        if(fh==STDOUT||fh==STDERR){
                return -1;
        }
        if(fh==STDIN){
                return MESSAGE_SCANF(buf,len)?0:-1;
        }
#if SUPPORT_FILE_SYSTEM                
        fr = f_read((FIL *)fh, buf, len, &br);
        if (fr == FR_OK)
                return len - br;
#endif
        return -1;
}

void _ttywrch(int ch)
{
        char c = ch;
        MESSAGE_PRINT(&c,1);
}

int _sys_istty(FILEHANDLE fh)
{
        return IS_STD(fh); /* buffered output */
}

int _sys_seek(FILEHANDLE fh, long pos)
{
#if SUPPORT_FILE_SYSTEM
        FRESULT fr;
        if(!IS_STD(fh)){
                fr = f_lseek((FIL *)fh, pos);
                if (fr == FR_OK)
                        return 0;
        }
#endif
        return -1;
}

long _sys_flen(FILEHANDLE fh)
{
#if SUPPORT_FILE_SYSTEM
        if (!IS_STD(fh))
                return f_size((FIL *)fh);
#endif
        return -1;
}
int _sys_ensure(FILEHANDLE fh){
#if SUPPORT_FILE_SYSTEM
        if (!IS_STD(fh)){
                if(f_sync((FIL*)fh)==FR_OK)
                        return 0;
        }
#endif
        return -1;
}
void _sys_exit(int code){
        printf("This Program unexpected exit! err:%d\r\n",code);
        while(1);
}

int remove(const char *pcPath){
#if SUPPORT_FILE_SYSTEM
        if(pcPath==__stdin_name||pcPath==__stdout_name||pcPath==__stderr_name)
                return -1;
        if(f_unlink(pcPath)==FR_OK)
                return 0;
#endif
        return -1;
}

//不清楚如何实现
int _sys_tmpnam(char * name, int sig, unsigned maxlen){
        return 0;
}

//重定向内存分配的相关库函数
#if SUPPORT_MALLOC
void *malloc (size_t size){
        return OS_Malloc(size);
}

void free(void* p){
        OS_Free(p);
}

void *realloc(void* p,size_t want){
        return OS_Realloc(p,want);
}

void *calloc(size_t nmemb, size_t size){
        return OS_Calloc(nmemb,size);
}

#endif

作者:EnzoSun
微信关注:勿忘初兴
本文出处:http://sunduoze.github.io/post/redefine_fopen_malloc/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。