logger(一):C++ & logger模块配置及开发
2016-01-12 14:42
417 查看
该logger模块是一种本地缓存形式的logger处理方法:用于相关软件开发过程中的日志记录;适用于windows和linux
Linux下的主要使用的是syslog-ng库,以下贴出源码,详情请下载开发包。
logger.h
-----------------------------------------------------------------------------------------------------------------------------
/*
* logger.h
* Author: ws
* Data: 2015-12-24
*/
#ifndef WS_LOGGER_H_
#define WS_LOGGER_H_
#include <cstdlib>
#include <cstdio>
#include <string>
//------------------------------------------------------------------------
// 日志系统
// 根据不同的系统使用不同的库
// 若是windows系统使用宏#define WIN32
// 若是linux系统中旧的log日志系统,使用宏#define L_LOG_OLD
// 若是linux系统中的syslog-ng日志系统(需要单独安装及配置),使用宏#define L_LOG_NG
//------------------------------------------------------------------------
//#define WIN32 // 表示使用的是windows系统
//#define L_LOG_OLD // 表示使用的是linux旧的syslog库
#define L_LOG_NG // 表示使用的是linux新的syslog-ng库,syslog的升级版
//-----------------------------------------------------------------------
// 声明部分
//-----------------------------------------------------------------------
# define MAXLOGLINE1024
#ifdef WIN32 // windows
//#define FOLDER_PATH // 表示日志地址是使用系统路径
#define MODEL_PATH // 表示日志地址是进程所在的文件路径
#include <fstream>
#include <shlwapi.h>
enum LogLevel {
Fatal = 0,//0 最高级,致命的
Alert = 1,//1
最高级,必须采取措施
Crit = 2,//2 最高级,临界状态
Error = 3,//3 高级,错误
Warn = 4,//4 高级,警告
Notice
= 5, //5 高级,正常但重要
Info = 6,//6 高级,一般信息
Debug = 7,//7 一般,调试信息
};
#else // "Linux syslog"(L_LOG_OLD) Or "linux syslog-ng"(L_LOG_NG)
#include <syslog.h>
enum LogLevel {
Fatal = LOG_EMERG,//0 最高级,致命的
Alert = LOG_ALERT,//1
最高级,必须采取措施
Crit = LOG_CRIT,//2 最高级,临界状态
Error = LOG_ERR,//3 高级,错误
Warn = LOG_WARNING,//4 高级,警告
Notice
= LOG_NOTICE, //5 高级,正常但重要
Info = LOG_INFO,//6 高级,一般信息
Debug = LOG_DEBUG,//7 一般,调试信息
};
#endif
//--------------------------------------------------------------
// 日志功能
//--------------------------------------------------------------
extern int syslogDevLevel; // 默认日志等级(默认等级debug)
void initLog(); // 初始化系统记录器
void logxxx(int l, char *file, int line, const char *fmt, ...); // 打印日志
void closeLog(); // 关闭log系统
int setLogLevel(); // 获取日志等级
int setLogLevel(int l); // 设置日志等级,返回旧的等级(这里不修改环境变量,防止更改所有进程的输出等级)
// 日志检测平台接入
struct ISyslogObserver {
virtual void watch(int level, const char *file, int line, const char *fmt, ...) = 0;
virtual bool interested(int level) = 0; // 判断是否对当前Level感兴趣,感兴趣才传递过去
virtual ~ISyslogObserver(){}
};
extern ISyslogObserver * SyslogWatcher; // 系统日志检测
extern ISyslogObserver * logStatWatcher; // 日志状态检测
// 日志
#define log(l, ...) \
if (SyslogWatcher && SyslogWatcher->interested(l)) { SyslogWatcher->watch(l, __FILE__, __LINE__, __VA_ARGS__); } \
if (logStatWatcher && logStatWatcher->interested(l)) { logStatWatcher->watch(l, __FILE__, __LINE__, __VA_ARGS__); } \
if (syslogDevLevel >= l) {logxxx(l, (char *)__FILE__, __LINE__, __VA_ARGS__); }
#endif // WS_LOGGER_H_
logger.cpp
--------------------------------------------------------------------------------------------------------------------------------------------
/*
* logger.cpp
* Author: ws
* Data: 2015-12-24
*/
//--------------------------------------------------------------
// 日志系统
//--------------------------------------------------------------
#include "logger.h"
#include <iostream>
#include <stdarg.h>
#include <ctime>
#include <cassert>
#include <stdlib.h>
#ifdef WIN32 // windows
#include <tchar.h>
#include <shlobj.h>
#include <windows.h>
#else // linux
#include <syslog.h>
#ifdef L_LOG_NG // linux syslog-ng
#include "syslog-nb.h"
#endif
#endif
#include <iostream>
using namespace std;
//--------------------------------------------------------------
// 全局变量
//--------------------------------------------------------------
ISyslogObserver * SyslogWatcher = NULL;
ISyslogObserver * logStatWatcher = NULL;
char * pDevLevel = getenv("DEV_LOG_LEVEL"); // 获取环境变量,系统默认日志等级
int syslogDevLevel = (NULL == pDevLevel) ? Debug : atol(pDevLevel);
// 获取日志等级
int setLogLevel()
{
return syslogDevLevel;
}
// 设置日志等级,返回旧的等级(这里不修改环境变量,防止更改所有进程的输出等级)
int setLogLevel(int l)
{
int old_level = syslogDevLevel;
syslogDevLevel = l;
return old_level;
}
#ifdef WIN32 // windows
std::ofstream fout; // 文件句柄
static long __log_lock = 0; //加锁计数器
// 等级名称
const char * levelnames[] = { "Fatal - ", "Alert - ", "Crit - ", "Error - ", "Warn - ", "Notice - ", "Info - ", "Debug - ", " - " };
const char * LevelToName(int l) {
return levelnames[l];
}
// 获取当前时间
std::string safe_time()
{
time_t t = time(NULL);
char *ct = ctime(&t);
if(ct){
size_t len = strlen(ct);
if(len > 0){
ct[len - 1] = '\0';
return std::string(ct, len - 1);
}
}
return "empty time";
}
// 长字符串转短
std::string Wchar2Ansi(const wchar_t* pStr, int len)
{
int nChars = 0;
std::string buf;
if (pStr == NULL)
{
assert(NULL);
return buf;
}
if (len < 0 && len != -1)
{
assert(NULL);
//OutputDebugStringW(_T("Invalid string length: ") + len); // 调试器
return buf;
}
// 长转短
nChars = WideCharToMultiByte(CP_ACP, 0, pStr, len, NULL, 0, NULL, NULL);
if (len == -1)
--nChars;
if (nChars == 0)
return "";
buf.resize(nChars);
WideCharToMultiByte(CP_ACP, 0, pStr, len, const_cast<char*>(buf.c_str()), nChars, NULL, NULL);
return buf;
}
// 短转长
std::wstring Ansi2WChar(LPCSTR pszSrc)
{
int nSize = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, _tcslen(pszSrc), 0, 0);
if (nSize <= 0) return NULL;
WCHAR *pwszDst = new WCHAR[nSize + 1];
if (NULL == pwszDst) return NULL;
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, _tcslen(pszSrc), pwszDst, nSize);
pwszDst[nSize] = 0;
if (pwszDst[0] == 0xFEFF) // skip Oxfeff
{
for (int i = 0; i < nSize; i++)
{
pwszDst[i] = pwszDst[i + 1];
}
}
std::wstring wcharString(pwszDst);
delete pwszDst;
return wcharString;
}
// 解析出文件路径
std::string GetFileDirFromPath(LPCTSTR filepath)
{
unsigned int orgLen = _tcslen(filepath);
TCHAR end = filepath[orgLen - 1];
if (end != _T('\\') && end != _T(':'))
{
LPCTSTR FN = PathFindFileName(filepath); // 获取路径中的文件名
return std::string(filepath, orgLen - _tcslen(FN));
}
else
{
return std::string(filepath);
}
}
// 获取当前模块进程文件所在的路径
std::string GetModulePathDir()
{
TCHAR buffer[MAX_PATH];
ZeroMemory(buffer, sizeof(TCHAR) * MAX_PATH);
::GetModuleFileName(NULL, buffer, MAX_PATH); // 获取当前进程模块的文件名,含路径
std::string path = GetFileDirFromPath(buffer); // 获取文件路径
return path;
}
// 字符串中特殊字符替换
static std::string TransformInstallPath2FolderName(std::string const& strPath)
{
std::string strReturn;
strReturn.resize(strPath.size());
for (size_t i = 0; i < strPath.length(); i++)
{
TCHAR c = TCHAR(strPath[i]);
if (c == _T(':') || c == _T('\\') || c == _T(' ') || c == _T('/'))
{
strReturn[i] = _T('_');
}
else
{
strReturn[i] = strPath[i];
}
}
return strReturn;
}
// 获取指定系统路径
std::wstring GetUserAppDataDir()
{
TCHAR buffer[MAX_PATH];
ZeroMemory(buffer, MAX_PATH*sizeof(TCHAR));
SHGetSpecialFolderPath(NULL,buffer, CSIDL_APPDATA, NULL); // 获取指定系统路径
std::string path = std::string(buffer) + _T("\\ws\\");
path += TransformInstallPath2FolderName(GetModulePathDir());
path += _T("\\");
int nReturn = SHCreateDirectoryEx(NULL, path.c_str(), NULL);
std::wstring strPath = Ansi2WChar(path.c_str());
return strPath;
}
//-----------------------------------------
// 功能部分
//-----------------------------------------
// 初始化系统记录器,获取日志文件路径
void initLog() {
char buffer[MAX_PATH * 2];
ZeroMemory(buffer, sizeof(char) * MAX_PATH * 2);
std::string str;
#ifdef MODEL_PATH // 表示日志地址是进程所在的文件路径
str = GetModulePathDir();
#else // 表示日志地址是使用系统路径
std::wstring strW = GetUserAppDataDir();
strW = Wchar2Ansi(strW.c_str(), strW.length());
#endif
sprintf(buffer, "%sprotocol.log", str.data());
fout.open(buffer, std::ios_base::trunc);
fout << "program start: " << safe_time() << std::endl;
}
// 输出log
void logxxx(int l, char *file, int line, const char *fmt, ...)
{
va_list
param;
va_start(param, fmt);
// 锁
while (true)
{
if (InterlockedIncrement(&__log_lock) == 1)
{
break;
}
InterlockedDecrement(&__log_lock);
}
if (l <= syslogDevLevel)
{
char buf[MAXLOGLINE * 4];
_vsnprintf(buf, MAXLOGLINE * 4, fmt, param);
fout << safe_time()<< file << line << ":" << LevelToName(l) << buf << std::endl;
fout.flush();
}
InterlockedDecrement(&__log_lock);
va_end(param);
}
// 关闭log系统
void closeLog()
{
fout << "program end:" << safe_time() << std::endl;
fout.close();
}
#else // linux
//--------------------------------------------------------------
// 日志系统
//--------------------------------------------------------------
// 初始化系统记录器
void initLog(){
#ifdef L_LOG_OLD // "Linux syslog"(L_LOG_OLD)
openlog(NULL, LOG_PID, LOG_LOCAL0); // LOG_PID:包括每个消息的进程号; LOG_LOCAL0:保留到本地
#else // "linux syslog-ng"(L_LOG_NG)
openlog_nb(NULL, LOG_PID, LOG_LOCAL0); // LOG_PID:包括每个消息的进程号; LOG_LOCAL0:保留到本地
#endif
}
// 输出log
void logxxx(int l, char *file, int line, const char *fmt, ...) {
if (l <= syslogDevLevel) {
char msg[MAXLOGLINE];
va_list
ap;
va_start(ap, fmt);
int ret = vsnprintf(msg, MAXLOGLINE, fmt, ap);
va_end(ap);
if (ret < 0) { return; }
#ifdef L_LOG_OLD // "Linux syslog"(L_LOG_OLD)
syslog(l, "[%s:%d]: %s\n", file, line, msg);
#else // "linux syslog-ng"(L_LOG_NG)
syslog_nb(l, "[%s:%d]: %s\n", file, line, msg);
#endif
}
else
{
return;
}
}
// 关闭log系统
void closeLog()
{
#ifdef L_LOG_OLD // "Linux syslog"(L_LOG_OLD)
closelog();
#else // "linux syslog-ng"(L_LOG_NG)
closelog_nb();
#endif
}
#endif
--------------------------------------------------------------
配置信息请参照下一篇:syslog &syslog-ng详解
Linux下的主要使用的是syslog-ng库,以下贴出源码,详情请下载开发包。
logger.h
-----------------------------------------------------------------------------------------------------------------------------
/*
* logger.h
* Author: ws
* Data: 2015-12-24
*/
#ifndef WS_LOGGER_H_
#define WS_LOGGER_H_
#include <cstdlib>
#include <cstdio>
#include <string>
//------------------------------------------------------------------------
// 日志系统
// 根据不同的系统使用不同的库
// 若是windows系统使用宏#define WIN32
// 若是linux系统中旧的log日志系统,使用宏#define L_LOG_OLD
// 若是linux系统中的syslog-ng日志系统(需要单独安装及配置),使用宏#define L_LOG_NG
//------------------------------------------------------------------------
//#define WIN32 // 表示使用的是windows系统
//#define L_LOG_OLD // 表示使用的是linux旧的syslog库
#define L_LOG_NG // 表示使用的是linux新的syslog-ng库,syslog的升级版
//-----------------------------------------------------------------------
// 声明部分
//-----------------------------------------------------------------------
# define MAXLOGLINE1024
#ifdef WIN32 // windows
//#define FOLDER_PATH // 表示日志地址是使用系统路径
#define MODEL_PATH // 表示日志地址是进程所在的文件路径
#include <fstream>
#include <shlwapi.h>
enum LogLevel {
Fatal = 0,//0 最高级,致命的
Alert = 1,//1
最高级,必须采取措施
Crit = 2,//2 最高级,临界状态
Error = 3,//3 高级,错误
Warn = 4,//4 高级,警告
Notice
= 5, //5 高级,正常但重要
Info = 6,//6 高级,一般信息
Debug = 7,//7 一般,调试信息
};
#else // "Linux syslog"(L_LOG_OLD) Or "linux syslog-ng"(L_LOG_NG)
#include <syslog.h>
enum LogLevel {
Fatal = LOG_EMERG,//0 最高级,致命的
Alert = LOG_ALERT,//1
最高级,必须采取措施
Crit = LOG_CRIT,//2 最高级,临界状态
Error = LOG_ERR,//3 高级,错误
Warn = LOG_WARNING,//4 高级,警告
Notice
= LOG_NOTICE, //5 高级,正常但重要
Info = LOG_INFO,//6 高级,一般信息
Debug = LOG_DEBUG,//7 一般,调试信息
};
#endif
//--------------------------------------------------------------
// 日志功能
//--------------------------------------------------------------
extern int syslogDevLevel; // 默认日志等级(默认等级debug)
void initLog(); // 初始化系统记录器
void logxxx(int l, char *file, int line, const char *fmt, ...); // 打印日志
void closeLog(); // 关闭log系统
int setLogLevel(); // 获取日志等级
int setLogLevel(int l); // 设置日志等级,返回旧的等级(这里不修改环境变量,防止更改所有进程的输出等级)
// 日志检测平台接入
struct ISyslogObserver {
virtual void watch(int level, const char *file, int line, const char *fmt, ...) = 0;
virtual bool interested(int level) = 0; // 判断是否对当前Level感兴趣,感兴趣才传递过去
virtual ~ISyslogObserver(){}
};
extern ISyslogObserver * SyslogWatcher; // 系统日志检测
extern ISyslogObserver * logStatWatcher; // 日志状态检测
// 日志
#define log(l, ...) \
if (SyslogWatcher && SyslogWatcher->interested(l)) { SyslogWatcher->watch(l, __FILE__, __LINE__, __VA_ARGS__); } \
if (logStatWatcher && logStatWatcher->interested(l)) { logStatWatcher->watch(l, __FILE__, __LINE__, __VA_ARGS__); } \
if (syslogDevLevel >= l) {logxxx(l, (char *)__FILE__, __LINE__, __VA_ARGS__); }
#endif // WS_LOGGER_H_
logger.cpp
--------------------------------------------------------------------------------------------------------------------------------------------
/*
* logger.cpp
* Author: ws
* Data: 2015-12-24
*/
//--------------------------------------------------------------
// 日志系统
//--------------------------------------------------------------
#include "logger.h"
#include <iostream>
#include <stdarg.h>
#include <ctime>
#include <cassert>
#include <stdlib.h>
#ifdef WIN32 // windows
#include <tchar.h>
#include <shlobj.h>
#include <windows.h>
#else // linux
#include <syslog.h>
#ifdef L_LOG_NG // linux syslog-ng
#include "syslog-nb.h"
#endif
#endif
#include <iostream>
using namespace std;
//--------------------------------------------------------------
// 全局变量
//--------------------------------------------------------------
ISyslogObserver * SyslogWatcher = NULL;
ISyslogObserver * logStatWatcher = NULL;
char * pDevLevel = getenv("DEV_LOG_LEVEL"); // 获取环境变量,系统默认日志等级
int syslogDevLevel = (NULL == pDevLevel) ? Debug : atol(pDevLevel);
// 获取日志等级
int setLogLevel()
{
return syslogDevLevel;
}
// 设置日志等级,返回旧的等级(这里不修改环境变量,防止更改所有进程的输出等级)
int setLogLevel(int l)
{
int old_level = syslogDevLevel;
syslogDevLevel = l;
return old_level;
}
#ifdef WIN32 // windows
std::ofstream fout; // 文件句柄
static long __log_lock = 0; //加锁计数器
// 等级名称
const char * levelnames[] = { "Fatal - ", "Alert - ", "Crit - ", "Error - ", "Warn - ", "Notice - ", "Info - ", "Debug - ", " - " };
const char * LevelToName(int l) {
return levelnames[l];
}
// 获取当前时间
std::string safe_time()
{
time_t t = time(NULL);
char *ct = ctime(&t);
if(ct){
size_t len = strlen(ct);
if(len > 0){
ct[len - 1] = '\0';
return std::string(ct, len - 1);
}
}
return "empty time";
}
// 长字符串转短
std::string Wchar2Ansi(const wchar_t* pStr, int len)
{
int nChars = 0;
std::string buf;
if (pStr == NULL)
{
assert(NULL);
return buf;
}
if (len < 0 && len != -1)
{
assert(NULL);
//OutputDebugStringW(_T("Invalid string length: ") + len); // 调试器
return buf;
}
// 长转短
nChars = WideCharToMultiByte(CP_ACP, 0, pStr, len, NULL, 0, NULL, NULL);
if (len == -1)
--nChars;
if (nChars == 0)
return "";
buf.resize(nChars);
WideCharToMultiByte(CP_ACP, 0, pStr, len, const_cast<char*>(buf.c_str()), nChars, NULL, NULL);
return buf;
}
// 短转长
std::wstring Ansi2WChar(LPCSTR pszSrc)
{
int nSize = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, _tcslen(pszSrc), 0, 0);
if (nSize <= 0) return NULL;
WCHAR *pwszDst = new WCHAR[nSize + 1];
if (NULL == pwszDst) return NULL;
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, _tcslen(pszSrc), pwszDst, nSize);
pwszDst[nSize] = 0;
if (pwszDst[0] == 0xFEFF) // skip Oxfeff
{
for (int i = 0; i < nSize; i++)
{
pwszDst[i] = pwszDst[i + 1];
}
}
std::wstring wcharString(pwszDst);
delete pwszDst;
return wcharString;
}
// 解析出文件路径
std::string GetFileDirFromPath(LPCTSTR filepath)
{
unsigned int orgLen = _tcslen(filepath);
TCHAR end = filepath[orgLen - 1];
if (end != _T('\\') && end != _T(':'))
{
LPCTSTR FN = PathFindFileName(filepath); // 获取路径中的文件名
return std::string(filepath, orgLen - _tcslen(FN));
}
else
{
return std::string(filepath);
}
}
// 获取当前模块进程文件所在的路径
std::string GetModulePathDir()
{
TCHAR buffer[MAX_PATH];
ZeroMemory(buffer, sizeof(TCHAR) * MAX_PATH);
::GetModuleFileName(NULL, buffer, MAX_PATH); // 获取当前进程模块的文件名,含路径
std::string path = GetFileDirFromPath(buffer); // 获取文件路径
return path;
}
// 字符串中特殊字符替换
static std::string TransformInstallPath2FolderName(std::string const& strPath)
{
std::string strReturn;
strReturn.resize(strPath.size());
for (size_t i = 0; i < strPath.length(); i++)
{
TCHAR c = TCHAR(strPath[i]);
if (c == _T(':') || c == _T('\\') || c == _T(' ') || c == _T('/'))
{
strReturn[i] = _T('_');
}
else
{
strReturn[i] = strPath[i];
}
}
return strReturn;
}
// 获取指定系统路径
std::wstring GetUserAppDataDir()
{
TCHAR buffer[MAX_PATH];
ZeroMemory(buffer, MAX_PATH*sizeof(TCHAR));
SHGetSpecialFolderPath(NULL,buffer, CSIDL_APPDATA, NULL); // 获取指定系统路径
std::string path = std::string(buffer) + _T("\\ws\\");
path += TransformInstallPath2FolderName(GetModulePathDir());
path += _T("\\");
int nReturn = SHCreateDirectoryEx(NULL, path.c_str(), NULL);
std::wstring strPath = Ansi2WChar(path.c_str());
return strPath;
}
//-----------------------------------------
// 功能部分
//-----------------------------------------
// 初始化系统记录器,获取日志文件路径
void initLog() {
char buffer[MAX_PATH * 2];
ZeroMemory(buffer, sizeof(char) * MAX_PATH * 2);
std::string str;
#ifdef MODEL_PATH // 表示日志地址是进程所在的文件路径
str = GetModulePathDir();
#else // 表示日志地址是使用系统路径
std::wstring strW = GetUserAppDataDir();
strW = Wchar2Ansi(strW.c_str(), strW.length());
#endif
sprintf(buffer, "%sprotocol.log", str.data());
fout.open(buffer, std::ios_base::trunc);
fout << "program start: " << safe_time() << std::endl;
}
// 输出log
void logxxx(int l, char *file, int line, const char *fmt, ...)
{
va_list
param;
va_start(param, fmt);
// 锁
while (true)
{
if (InterlockedIncrement(&__log_lock) == 1)
{
break;
}
InterlockedDecrement(&__log_lock);
}
if (l <= syslogDevLevel)
{
char buf[MAXLOGLINE * 4];
_vsnprintf(buf, MAXLOGLINE * 4, fmt, param);
fout << safe_time()<< file << line << ":" << LevelToName(l) << buf << std::endl;
fout.flush();
}
InterlockedDecrement(&__log_lock);
va_end(param);
}
// 关闭log系统
void closeLog()
{
fout << "program end:" << safe_time() << std::endl;
fout.close();
}
#else // linux
//--------------------------------------------------------------
// 日志系统
//--------------------------------------------------------------
// 初始化系统记录器
void initLog(){
#ifdef L_LOG_OLD // "Linux syslog"(L_LOG_OLD)
openlog(NULL, LOG_PID, LOG_LOCAL0); // LOG_PID:包括每个消息的进程号; LOG_LOCAL0:保留到本地
#else // "linux syslog-ng"(L_LOG_NG)
openlog_nb(NULL, LOG_PID, LOG_LOCAL0); // LOG_PID:包括每个消息的进程号; LOG_LOCAL0:保留到本地
#endif
}
// 输出log
void logxxx(int l, char *file, int line, const char *fmt, ...) {
if (l <= syslogDevLevel) {
char msg[MAXLOGLINE];
va_list
ap;
va_start(ap, fmt);
int ret = vsnprintf(msg, MAXLOGLINE, fmt, ap);
va_end(ap);
if (ret < 0) { return; }
#ifdef L_LOG_OLD // "Linux syslog"(L_LOG_OLD)
syslog(l, "[%s:%d]: %s\n", file, line, msg);
#else // "linux syslog-ng"(L_LOG_NG)
syslog_nb(l, "[%s:%d]: %s\n", file, line, msg);
#endif
}
else
{
return;
}
}
// 关闭log系统
void closeLog()
{
#ifdef L_LOG_OLD // "Linux syslog"(L_LOG_OLD)
closelog();
#else // "linux syslog-ng"(L_LOG_NG)
closelog_nb();
#endif
}
#endif
--------------------------------------------------------------
配置信息请参照下一篇:syslog &syslog-ng详解
相关文章推荐
- 学习制作dll文件,并在MFC项目内调用
- C++11内存模型
- 【HDOJ】1699 The comment in cpp
- C++类四个默认函数---构造函数、析构函数、拷贝函数、赋值函数
- Delete characters删除两个字符串中相同的字符
- 多个类的DLL封装及调用
- 使用Lex将C/C++文件输出为HTML文件
- 转载_认识C语言的32个关键字
- java调用C++的过程?
- C语言-流程控制语句
- C语言-开发工具
- C语言-结构体与联合体
- C语言-基本数据类型
- C语言-函数
- C语言-标准库
- C语言-变量与常量
- C语言-编译与链接
- C语言-WIN32线程
- C语言-WIN32文件
- C语言-WIN32进程