C语言单例模式

单例模式的定义

​ 单例模式的需求是保证在代码的整个运行期间,某种数据类型只有一个唯一的实例子。并且提供一个全局的访问接口。

我们可以从两个角度来理解单例模式

  • 数据类型有且仅可以创建一个实例,编程人员不可以的随意的定义的此类型的实例。我们必须限制这种数据结构的创建。
  • 访问接口是全局唯一实例的访问接口。

单例模式的实现

​ 一般单例模式按照创建对象创建和调用的时序关系可分为懒汉式和饥汉式。饥汉式一般在程序启动时创建对象,非Lazy初始化;懒汉式在真正使用时在创建,采用Lazy初始化。

饿汉式

​ 饿汉式,就像饿汉一样,不论自身需要与否,在程序启动时即开始创建。在C++中一般声明为全局变量实现饿汉式,全局变量会在main函数执行之前创建全局变量对象,在main函数执行结束之后释放全局变量

	可执行程序有一个全局_CTOR_LIST函数指针数组,编译器在链接时会把全局变量的构造函数指针添加到_CTOR_LIST中;然后可执行程序在执行main函数之前,会遍历并执行此_CTOR_LIST中的所有函数指针,这样就完成了全局变量的构造。

	同样可执行程序也存在一个全局_DTOR_LIST函数指针数组,编译器在链接时会把全局变量的析构 函数指针添加到_DTOR_LIST;在可执行程序执行main函数之后,会遍历并执行此_DTOR_LIST中的所有函数指针,这样就完成了全局变量的析构。

​ 熟悉了C++饿汉式全局变量的构造过程,我们参考全局变量原理构造原理实现C语言饥汉式。幸运的是GCC和MSVC都提供了相应的机制实现main之前和之后调用函数。

​ 正好GCC提供了attribute关键字,可以通过声明constructor和destructor的函数,声明constructor的函数会在main函数之前调用,声明destructor函数会在main之后调用。

#include<stdio.h> 

// 声明一个constructor属性函数,此函数会在main之前运行
__attribute__((constructor)) void before() 
{  
   printf("run function before main\n"); 
} 

// 声明一个destructor属性函数,此函数会在main之后运行
__attribute__((destructor)) void after() 
{ 
   printf("run function after main\n"); 
} 
  
int main(int argc, char **argv) 
{ 
   printf("run main function\n"); 
   return 0; 
}

​ 结果表明,使用__attribute__关键词可以实现在main函数前运行语句,所以根据这个特性,我们可以实现GCC版本的饿汉单例版本。

案例

​ 结构声明

#pragma once

#include <stdio.h>
#include <stdlib.h>

typedef  void  File;

typedef enum BOOL
{
	FALSE = 0,
	TRUE = 1,
}BOOL;

typedef struct tagFileManager
{
	File* (*mkFile)(const char* fileName, char const* mode);
	BOOL  (*rmFile)(const char*  fileName);
	int   (*write)(File* file, const char* buf, int size);
	BOOL  (*exit)(const char* fileName);
	BOOL  (*close)(const File* file);
}FileManager;

实现说明

#include "file_manager.h"

#include <io.h>

static FileManager g_fileManager;

typedef int constructor();

static File* mkFile(const char* fileName, char const* mode);
static BOOL rmFile(const char* fileName);
static int fileWrite(File* file, const char* buf, int size);
static BOOL isExit(const char* fileName);
static BOOL fileClose(const File* file);

File* mkFile(const char* fileName, char const* mode)
{
	FILE* file = NULL;
	if (0 == fopen_s(&file, fileName, mode))
	{
		return file;
	}
	
	return NULL;
}

BOOL rmFile(const char* fileName)
{
	if (isExit(fileName))
	{
		return !remove(fileName);
	}
}

int fileWrite(File* file, const char* buf, int size)
{
	return fwrite(buf, size, 1, file);
}

BOOL isExit(const char* fileName)
{
	return (_access(fileName, 0) == 0);
}

BOOL fileClose(const File* file)
{
	return !fclose(file);
}

__attribute__((constructor)) static int ctor()
{
	g_fileManager.exit = isExit;
	g_fileManager.mkFile = mkFile;
	g_fileManager.rmFile = rmFile;
	g_fileManager.write = fileWrite;
	g_fileManager.close = fileClose;
	return 0;
}

__attribute__((destructor)) static int dtor()
{
	g_fileManager.exit = NULL;
	g_fileManager.mkFile = NULL;
	g_fileManager.rmFile = NULL;
	g_fileManager.write = NULL;
	g_fileManager.close = NULL;
	return 0;
}

FileManager* fileManager()
{
	return &g_fileManager;
}

posted @ 2023-07-07 19:12  Kroner  阅读(159)  评论(1编辑  收藏  举报