基础知识
- 在一个宏中的参数前面使用一个#,预处理器会把这个参数转换为一个字符数组
- ##是一种分隔连接方式,它的作用是先分隔,然后进行强制连接
- 宏中遇到#或##时就不会再展开宏中嵌套的宏了
- 宏定义中do{ }while(0)
-
空的宏定义避免warning:
-
存在一个独立的block,可以用来进行变量定义,进行比较复杂的实现。
-
如果出现在判断语句过后的宏,这样可以保证作为一个整体来是实现
-
在把宏引入代码中,会多出一个分号,从而会报错。这对这一点,可以将if和else语句用{}括起来,可以避免分号错误
#include <stdio.h>
#define MACRO_FUNC(cond) \
do { \
if (cond) \
(void)0;\
else \
AssertFailure_(__func__, __FILE__, __LINE__, #cond);\
} while (0)
void AssertFailure_(const char *func, const char *file, int line,const char *cond_str){
printf("%s,%s,%d,%s\n",func,file,line,cond_str);
}
int main()
{
if(2 > 1)
MACRO_FUNC(0);
else
printf("Fail.\n");
return 0;
}
main,macrot.cpp,17,0
#include <stdio.h>
void action1(){
printf("======\n");
}
void action2(){
printf("++++++\n");
}
#define foo(x) \
action1(); \
action2();
#define switch_(x,y) {int tmp; tmp=x;x=y;y=tmp;}
int main(){
if(true)
for (int i = 0; i < 2; ++i)
foo();
int x = 3;
int y = 4;
if(x>y){
switch_(x,y);
}
else{
printf("exp3\n");
}
return 0;
}
综合知识
例一:基本宏函数替换
#include<stdio.h>
#include <cassert>
#include <iostream>
#include <string>
#define DEBUG_PRINT(msg) do{printf("%s - %s - line:%d, file:%s", __DATE__, __TIME__, __LINE__, __FILE__);printf(msg);}while(0)
using std::string;
class LogMessage {
public:
LogMessage(const string &type) : fatal_(type == "FATAL") {
std::cerr << type << ": ";
}
~LogMessage() {
std::cerr << std::endl;
printf("12349999999");
if(fatal_)
exit(1);
}
std::ostream &stream() { return std::cerr; }
private:
bool fatal_;
};
#define CHECK(x) FstCheck(static_cast<bool>(x), #x, __FILE__, __LINE__)
#define LOG(type) LogMessage(#type).stream()
inline void FstCheck(bool x, const char* expr,
const char *file, int line) {
if (!x) {
LOG(FATAL) << "Check failed: \"" << expr
<< "\" file: " << file
<< " line: " << line;
}
}
#define TOW (2)
#define MUL(a,b) (a*b)
int main()
{
CHECK(1);
printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW));
printf("%d*%d=%d\n", (2), (2), ((2)*(2)));
return 0;
}
例二:宏函数包装一层可以实现宏函数替换,并查看中间替换结果
#include<stdio.h>
#include <cassert>
#include <iostream>
#include <string>
using std::string;
template <typename T>
class FlagRegister {
public:
static FlagRegister<T> *GetRegister() {
static auto reg = new FlagRegister<T>;
return reg;
}
};
template <typename T>
struct FlagDescription {
FlagDescription(T *addr, const char *doc, const char *type,
const char *file, const T val)
: address(addr),
doc_string(doc),
type_name(type),
file_name(file),
default_value(val) {}
T *address;
const char *doc_string;
const char *type_name;
const char *file_name;
const T default_value;
};
template <typename T>
class FlagRegisterer {
public:
FlagRegisterer(const string &name, const FlagDescription<T> &desc) {
auto registr = FlagRegister<T>::GetRegister();
registr->SetDescription(name, desc);
}
private:
FlagRegisterer(const FlagRegisterer &) = delete;
FlagRegisterer &operator=(const FlagRegisterer &) = delete;
};
#define DEFINE_VAR(type, name, value, doc) \
type FLAGS_ ## name = value; \
static FlagRegisterer<type> \
name ## _flags_registerer(#name, FlagDescription<type>(&FLAGS_ ## name, \
doc, \
#type, \
__FILE__, \
value))
#define DEFINE_bool(name, value, doc) DEFINE_VAR(bool, name, value, doc)
#define _STR(x) #x
#define STR(x) _STR(x)
int main()
{
printf(STR(DEFINE_VAR(bool,keep_isymbols, false, "Store input label symbol table with FST")));
return 0;
}
输出
bool FLAGS_keep_isymbols = false; static FlagRegisterer keep_isymbols_flags_registerer(“keep_isymbols”, FlagDescription(&FLAGS_keep_isymbols, “Store input label symbol table with FST”, “bool”, “tdefine.cc”, false))
例三:检查指针
#include <iostream>
using namespace std;
#define CHECK_NOTNULL(val) \
CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
template <typename T>
T* CheckNotNull(const char* file, int line, const char *names, T* ptr)
{
if (ptr == NULL)
{
cout << file << " " << line << ":" << names << endl;
}
return ptr;
}
int main(){
int *p;
*p = 5;
CHECK_NOTNULL(p);
int *q=CHECK_NOTNULL(p);
q=NULL;
CHECK_NOTNULL(q);
return 0;
}
例四: 模版嵌入
Arctest.cpp
#include<iostream>
#include <string>
#include "generic-register.h"
namespace fst {
template <class Arc>
class Fst;
struct FstReadOptions;
template <class Arc>
struct FstRegisterEntry {
using Reader = Fst<Arc> *(*)(std::istream &istrm, const FstReadOptions &opts);
using Converter = Fst<Arc> *(*)(const Fst<Arc> &fst);
Reader reader;
Converter converter;
explicit FstRegisterEntry(Reader reader = nullptr,
Converter converter = nullptr)
: reader(reader), converter(converter) {}
};
template <class Arc>
class FstRegister
: public GenericRegister<string, FstRegisterEntry<Arc>, FstRegister<Arc>> {
public:
using Reader = typename FstRegisterEntry<Arc>::Reader;
using Converter = typename FstRegisterEntry<Arc>::Converter;
const Reader GetReader(const string &type) const {
return this->GetEntry(type).reader;
}
const Converter GetConverter(const string &type) const {
return this->GetEntry(type).converter;
}
protected:
string ConvertKeyToSoFilename(const string &key) const override {
string legal_type(key);
return legal_type + "-fst.so";
}
};
template <class FST>
class FstRegisterer : public GenericRegisterer<FstRegister<typename FST::Arc>> {
public:
using Arc = typename FST::Arc;
using Entry = typename FstRegister<Arc>::Entry;
using Reader = typename FstRegister<Arc>::Reader;
FstRegisterer()
: GenericRegisterer<FstRegister<typename FST::Arc>>(FST().Type(),
BuildEntry()) {}
private:
static Entry BuildEntry() {
FST *(*reader)(std::istream & strm, const FstReadOptions &opts) =
&FST::Read;
return Entry(reinterpret_cast<Reader>(reader),
&FstRegisterer<FST>::Convert);
}
static Fst<Arc> *Convert(const Fst<Arc> &fst) { return new FST(fst); }
};
#define REGISTER_FST(FST, Arc) \
static fst::FstRegisterer<FST<Arc>> FST##_##Arc##_registerer
template <class Arc>
Fst<Arc> *Convert(const Fst<Arc> &fst, const string &fst_type) {
auto *reg = FstRegister<Arc>::GetRegister();
const auto converter = reg->GetConverter(fst_type);
if (!converter) {
cout << "Fst::Convert: Unknown FST type " << fst_type << " (arc type "
<< Arc::Type() << ")";
return nullptr;
}
return converter(fst);
}
}
#define _STR(x) #x
#define STR(x) _STR(x)
int main()
{
std::cout << STR(REGISTER_FST(A,B)) << std::endl;
return 0;
}
register.h
#include <string>
namespace fst {
template <class Arc>
class Fst;
struct FstReadOptions;
template <class Arc>
struct FstRegisterEntry {
using Reader = Fst<Arc> *(*)(std::istream &istrm, const FstReadOptions &opts);
using Converter = Fst<Arc> *(*)(const Fst<Arc> &fst);
Reader reader;
Converter converter;
explicit FstRegisterEntry(Reader reader = nullptr,
Converter converter = nullptr)
: reader(reader), converter(converter) {}
};
template <class Arc>
class FstRegister
: public GenericRegister<string, FstRegisterEntry<Arc>, FstRegister<Arc>> {
public:
using Reader = typename FstRegisterEntry<Arc>::Reader;
using Converter = typename FstRegisterEntry<Arc>::Converter;
const Reader GetReader(const string &type) const {
return this->GetEntry(type).reader;
}
const Converter GetConverter(const string &type) const {
return this->GetEntry(type).converter;
}
protected:
string ConvertKeyToSoFilename(const string &key) const override {
string legal_type(key);
ConvertToLegalCSymbol(&legal_type);
return legal_type + "-fst.so";
}
};
template <class FST>
class FstRegisterer : public GenericRegisterer<FstRegister<typename FST::Arc>> {
public:
using Arc = typename FST::Arc;
using Entry = typename FstRegister<Arc>::Entry;
using Reader = typename FstRegister<Arc>::Reader;
FstRegisterer()
: GenericRegisterer<FstRegister<typename FST::Arc>>(FST().Type(),
BuildEntry()) {}
private:
static Entry BuildEntry() {
FST *(*reader)(std::istream & strm, const FstReadOptions &opts) =
&FST::Read;
return Entry(reinterpret_cast<Reader>(reader),
&FstRegisterer<FST>::Convert);
}
static Fst<Arc> *Convert(const Fst<Arc> &fst) { return new FST(fst); }
};
#define REGISTER_FST(FST, Arc) \
static fst::FstRegisterer<FST<Arc>> FST##_##Arc##_registerer
template <class Arc>
Fst<Arc> *Convert(const Fst<Arc> &fst, const string &fst_type) {
auto *reg = FstRegister<Arc>::GetRegister();
const auto converter = reg->GetConverter(fst_type);
if (!converter) {
FSTERROR() << "Fst::Convert: Unknown FST type " << fst_type << " (arc type "
<< Arc::Type() << ")";
return nullptr;
}
return converter(fst);
}
}
generic-register.h
#include <string>
namespace fst {
template <class Arc>
class Fst;
struct FstReadOptions;
template <class Arc>
struct FstRegisterEntry {
using Reader = Fst<Arc> *(*)(std::istream &istrm, const FstReadOptions &opts);
using Converter = Fst<Arc> *(*)(const Fst<Arc> &fst);
Reader reader;
Converter converter;
explicit FstRegisterEntry(Reader reader = nullptr,
Converter converter = nullptr)
: reader(reader), converter(converter) {}
};
template <class Arc>
class FstRegister
: public GenericRegister<string, FstRegisterEntry<Arc>, FstRegister<Arc>> {
public:
using Reader = typename FstRegisterEntry<Arc>::Reader;
using Converter = typename FstRegisterEntry<Arc>::Converter;
const Reader GetReader(const string &type) const {
return this->GetEntry(type).reader;
}
const Converter GetConverter(const string &type) const {
return this->GetEntry(type).converter;
}
protected:
string ConvertKeyToSoFilename(const string &key) const override {
string legal_type(key);
ConvertToLegalCSymbol(&legal_type);
return legal_type + "-fst.so";
}
};
template <class FST>
class FstRegisterer : public GenericRegisterer<FstRegister<typename FST::Arc>> {
public:
using Arc = typename FST::Arc;
using Entry = typename FstRegister<Arc>::Entry;
using Reader = typename FstRegister<Arc>::Reader;
FstRegisterer()
: GenericRegisterer<FstRegister<typename FST::Arc>>(FST().Type(),
BuildEntry()) {}
private:
static Entry BuildEntry() {
FST *(*reader)(std::istream & strm, const FstReadOptions &opts) =
&FST::Read;
return Entry(reinterpret_cast<Reader>(reader),
&FstRegisterer<FST>::Convert);
}
static Fst<Arc> *Convert(const Fst<Arc> &fst) { return new FST(fst); }
};
#define REGISTER_FST(FST, Arc) \
static fst::FstRegisterer<FST<Arc>> FST##_##Arc##_registerer
template <class Arc>
Fst<Arc> *Convert(const Fst<Arc> &fst, const string &fst_type) {
auto *reg = FstRegister<Arc>::GetRegister();
const auto converter = reg->GetConverter(fst_type);
if (!converter) {
FSTERROR() << "Fst::Convert: Unknown FST type " << fst_type << " (arc type "
<< Arc::Type() << ")";
return nullptr;
}
return converter(fst);
}
}
例五 函数指针
#include <iostream>
#include <map>
typedef int (*mathfunc)(int,int);
typedef std::map<std::string, mathfunc> BrepMap;
BrepMap g_brew_map;
#define RegisterMathFunc(func) \
namespace { \
class __Register_##func{ \
public: \
__Register_##func() { g_brew_map[#func] = &func;}};\
__Register_##func g_register_##func;}
int add(int a, int b){
return a+b;
}
RegisterMathFunc(add)
int sub(int a, int b){
return a-b;
}
RegisterMathFunc(sub)
int mul(int a, int b){
return a*b;
}
RegisterMathFunc(mul)
int main()
{
std::cout<< "number of register functions: " << g_brew_map.size() << std::endl;
std::string math_method = "add";
std::cout << "23 + 12 = " << g_brew_map[math_method](23,12) << std::endl;
return 1;
}
number of register functions: 3
23 + 12 = 35