Simple MiniCRT

学习了程序员的自我修养这本书,对着示例CRT代码敲了一遍,收获还是颇丰的。

源码

  • string.c
#include <windows.h>
char* itoa(int n, char* str, int radix)
{
	char digit[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	char* p = str;
	char* head = str;
	if (!p || radix < 2 || radix > 36)
		return p;
	if (radix != 10 && n < 0)
		return p;
	if (n == 0)
	{
		*p++ = '0';
		*p = 0;
		return p;
	}
	if (radix == 10 && n < 0)
	{
		*p++ = '-';
		n = -n;
	}
	while (n)
	{
		*p++ = digit[n%radix];
		n /= radix;
	}
	*p = 0;
	for (--p; head < p; ++head, --p)
	{
		char temp = *head;
		*head = *p;
		*p = temp;
	}
	return str;
}

int strcmp(const char* src, const char* dst)
{
	int ret = 0;
	unsigned char* p1 = (unsigned char*)src;
	unsigned char* p2 = (unsigned char*)dst;
	while (!(ret = *p1 - *p2) && *p2)
		++p1, ++p2;
	if (ret < 0)
		ret = -1;
	else if (ret > 0)
		ret = 1;
	return ret;
}

char* strcpy(char* dest, const char* src)
{
	char* ret = dest;
	while (*src)
		*dest++ = *src++;
	*dest = '\0';
	return ret;
}

int strlen(const char* str)
{
	int cnt = 0;
	if (!str)
		return 0;
	for (; *str != '\0'; ++str)
		++cnt;
	return cnt;
}
  • stdio.c
#include "minicrt.h"
#include <windows.h>
int mini_crt_io_init()
{
	return 1;
}

FILE* fopen(const char* filename, const char* mode)
{
	HANDLE hFile = 0;
	int access = 0;
	int creation = 0;
	if (strcmp(mode, "w") == 0)
	{
		access |= GENERIC_WRITE;
		creation |= CREATE_ALWAYS;
	}
	if (strcmp(mode, "w+") == 0)
	{
		access |= GENERIC_WRITE | GENERIC_READ;
		creation |= CREATE_ALWAYS;
	}
	if (strcmp(mode, "r") == 0)
	{
		access |= GENERIC_READ;
		creation |= OPEN_EXISTING;
	}
	if (strcmp(mode, "r+") == 0)
	{
		access |= GENERIC_WRITE | GENERIC_READ;
		creation |= TRUNCATE_EXISTING;
	}
	hFile = CreateFileA(filename, access, 0, 0, creation, 0, 0);
	if (hFile == INVALID_HANDLE_VALUE)
		return 0;
	return (FILE*)hFile;
}

int fread(void* buffer, int size, int count, FILE* stream)
{
	int read = 0;
	if (!ReadFile((HANDLE)stream, buffer, size * count, &read, 0))
		return 0;
	return read;
}

int fwrite(const void* buffer, int size, int count, FILE* stream)
{
	int written = 0;
	if (!WriteFile((HANDLE)stream, buffer, size * count, &written, 0))
		return 0;
	return written;
}

int fclose(FILE* fp)
{
	return CloseHandle((HANDLE)fp);
}

int fseek(FILE* fp, int offset, int set)
{
	return SetFilePointer((HANDLE)fp, offset, 0, set);
}
  • entry.c
#include "minicrt.h"
#include <windows.h>

extern int main(int argc, char* argv[]);
void exit(int);

static void crt_fatal_error(const char* msg)
{
	//printf("fatal error: %s",msg);
	exit(1);
}
void mini_crt_entry(void)
{
	int ret;
	//Init part
	int flag = 0;
	int argc = 0;
	char* argv[16];//maximum 16 parameter
	char* cl = GetCommandLineA();
	//analyse command line
	argv[0] = cl;
	argc++;
	while (*cl)
	{
		if (*cl == '\"')
			if (flag == 0) flag = 1;
			else flag = 0;
		else if (*cl == ' '&&flag == 0)
		{
			if (*(cl + 1))
			{
				argv[argc] = cl + 1;
				argc++;
			}
			*cl = '\0';
		}
		cl++;
	}
	if (!mini_crt_heap_init())
		crt_fatal_error("heap initialize failed\n");
	if (!mini_crt_io_init())
		crt_fatal_error("IO initialize failed\n");
	

	ret = main(argc,argv);
	//exit part
	exit(ret);
}

void exit(int exitCode)
{
	ExitProcess(exitCode);
}


  • malloc.c
#include "minicrt.h"
#include <windows.h>
typedef struct _heap_header
{
	enum {
		HEAP_BLOCK_FREE = 0xABABABAB,
		HEAP_BLOCK_USED = 0xCDCDCDCD
	}type;
	unsigned size;
	struct _heap_header* next;
	struct _heap_header* prev;
}heap_header;

#define ADDR_ADD(a,o)(((char*)(a)) + o)
#define HEADER_SIZE (sizeof(heap_header))

static heap_header* list_head = NULL;

int mini_crt_heap_init()
{
	void* base = NULL;
	heap_header* header = NULL;
	//32 MB size HEAP
	unsigned int heap_size = 1024 * 1024 * 32;
	base = VirtualAlloc(0, heap_size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
	if (!base) return 0;
	header = (heap_header*)base;
	header->size = heap_size;
	header->type = HEAP_BLOCK_FREE;
	header->next = NULL;
	header->prev = NULL;
	list_head = header;
	return 1;
}

void* malloc(unsigned size)
{
	heap_header* header;
	if (!size)return NULL;
	header = list_head;

	while (header)
	{
		if (header->type == HEAP_BLOCK_USED)
		{
			header = header->next;
			continue;
		}
		if (header->size > size + HEADER_SIZE && header->size <= size + HEADER_SIZE * 2)
		{
			header->type = HEAP_BLOCK_USED;
			/*
				I do think this code have bug. When the last time you mark this block to USED (size is big)
				but when the size comes little this time,it actually can contains.
				Oh,I am wrong,the next time call malloc it can also get in next if QAQ.
			*/
		}
		if (header->size > size + HEADER_SIZE * 2)
		{
			// split
			heap_header* next = (heap_header*)ADDR_ADD(header, size + HEADER_SIZE);
			next->prev = header;
			next->next = header->next;
			next->type = HEAP_BLOCK_FREE;
			next->size = header->size - (size - HEADER_SIZE);
			header->next = next;
			header->size = size + HEADER_SIZE;
			header->type = HEAP_BLOCK_USED;
			return ADDR_ADD(header, HEADER_SIZE);
		}
		header = header->next;
	}
	return NULL;
}

void free(void* ptr)
{
	heap_header* header = (heap_header*)ADDR_ADD(ptr, -HEADER_SIZE);
	if (header->type != HEAP_BLOCK_USED)
		return;

	header->type = HEAP_BLOCK_FREE;

	// merge behind
	if (header->prev != NULL && header->prev->type == HEAP_BLOCK_FREE)
	{
		header->prev->next = header->next;
		if (header->next != NULL)
			header->next->prev = header->prev;
		header->prev->size += header->size;

		header = header->prev;
	}
	// merge after
	if (header->next != NULL && header->next->type == HEAP_BLOCK_FREE)
	{
		header->size += header->next->size;
		header->next = header->next->next;
	}

}
  • minicrt.h
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

//malloc
#ifndef NULL
#define NULL (0)
#endif

void free(void* ptr);
void* malloc(int size);
int mini_crt_init_heap();

//string
char* itoa(int n,char* str,int radix);
int strcmp(const char* src,const char* dst);
char* strcpy(char* dest,const char* src);
int strlen(const char* str);

//file & IO

typedef int FILE;
#define EOF (-1)
#define stdin ((FILE*)(GetStdHandle(STD_INPUT_HANDLE)))
#define stdout ((FILE*)(GetStdHandle(STD_OUTPUT_HANDLE)))
#define stderr ((FILE*)(GetStdHandle(STD_ERROR_HANDLE)))

int mini_crt_init_io();
FILE* fopen(const char* filename,const char* mode);
int fread(void* buffer,int size,int count,FILE* stream);
int fwrite(const void* buffer, int size, int count, FILE* stream);
int fclose(FILE* fp);
int fseek(FILE* fp, int offset, int set);

//printf
int fputc(int c, FILE* stream);
int fputs(const char* str, FILE* stream);
int printf(const char* format, ...);
int fprintf(FILE* stream,const char* format,...);

//internal
void do_global_ctors();
void mini_crt_call_exit_routine();

//atexit
typedef void (*atexit_func_t)(void);
int atexit(atexit_func_t func);



#ifdef __cplusplus
}
#endif
  • formatstr.c
#include "minicrt.h"
#include <windows.h>

int fputc(int c, FILE* stream)
{
	if (fwrite(&c, 1, 1, stream) != 1)
		return EOF;
	else
		return c;
}

int fputs(const char* str, FILE* stream)
{
	int len = strlen(str);
	if (fwrite(str, 1, len, stream) != len)
		return EOF;
	else
		return len;
}

int vfprintf(FILE* stream, const char* format, va_list arglist)
{
	// define a translate-normal pattern
	int translating = 0;
	int ret = 0;
	const char* p = 0;
	for (p = format; *p; p++)
	{
		switch (*p)
		{
		case '%':
			if (!translating)
				translating = 1;
			else
			{
				if (fputc('%', stream) < 0)
					return EOF;
				ret++;
				translating = 0;
			}
			break;
		case 'd':
			if (translating)
			{
				char buf[16];
				translating = 0;
				itoa(va_arg(arglist, int), buf, 10);
				if (fputs(buf, stream) < 0)
					return EOF;
				ret += strlen(buf);
			}
			else if (fputc('d', stream) < 0)
				return EOF;
			else
				ret++;
			break;
		case 's':
			if (translating)
			{
				const char* str = va_arg(arglist, const char*);
				translating = 0;
				if (fputs(str, stream) < 0)
					return EOF;
				ret += strlen(str);
			}
			else if (fputc('s', stream) < 0)
				return EOF;
			else
				ret++;
			break;
		default:
			if (!translating)
				translating = 0;
			if (fputc(*p, stream) < 0)
				return EOF;
			else
				ret++;
			break;
		}
		}
	return ret;
}

int printf(const char* format, ...)
{
	va_list(arglist);
	va_start(arglist, format);
	return vfprintf(stdout, format, arglist);
}

int fprintf(FILE* stream,const char* format,...)
{
	va_list(arglist);
	va_start(arglist, format);
	return vfprintf(stream, format, arglist);
}


测试代码

#include "minicrt.h"
int main(int argc,char* argv[])
{
	int i;
	FILE* fp;
	char** v = malloc(argc*sizeof(char*));
	for (i = 0; i < argc; i++)
	{
		v[i] = malloc(strlen(argv[i]) + 1);
		strcpy(v[i], argv[i]);
	}
	fp = fopen("test.txt", "w");
	for (i = 0; i < argc; i++)
	{
		int len = strlen(v[i]);
		fwrite(&len, 1, sizeof(int), fp);
		fwrite(v[i], 1, len, fp);		
	}
	fclose(fp);
	fp = fopen("test.txt", "r");
	for (i = 0; i < argc; i++)
	{
		int len;
		char* buf;
		fread(&len, 1, sizeof(int), fp);
		buf = malloc(len + 1);
		fread(buf, 1, len, fp);
		buf[len] = '\0';
		printf("%d %s\n", len, buf);
		free(buf);
		free(v[i]);
	}
	fclose(fp);
    return 0;
}
  • 已测试通过

编译方法

cl /c /DWIN32 /GS- entry.c malloc.c formatstr.c stdio.c string.c
lib entry.obj malloc.obj formatstr.obj stdio.obj string.obj /OUT:minicrt.lib

使用方法

cl /c /DWIN32 main.c
link main.obj minicrt.lib kernel32.lib /NODEFAULTLIB /entry:mini_crt_entry
dir main.exe
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值