用于替换循环的宏

时间:2015-12-13 04:08:48

标签: c header macros c-preprocessor

考虑下面的宏。如何使用宏展开for循环并将大量宏干净地导出到可读的标题中?

macro.h

#define ARR(n) \
typedef int arr##n[n]; \
void arr##n##_add(arr##n res, arr##n x, arr##n y){ \
    int i = 0; \
    for (; i < n; i++) { \
        res[i] = x[i] + y[i]; \
    } \
}

ARR(3)
ARR(4)

使用gcc -E -P macro.h > out.h通过预处理器执行此操作,我们得到:

out.h

typedef int arr3[3]; 

void arr3_add(arr3 res, arr3 x, arr3 y){ 
    int i = 0; 
    for (; i < 3; i++) { 
        res[i] = x[i] + y[i]; 
    } 
}

typedef int arr4[4]; 

void arr4_add(arr4 res, arr4 x, arr4 y){ 
    int i = 0; 
    for (; i < 4; i++) { 
        res[i] = x[i] + y[i]; 
    } 
}

使用上面的token pasting,我们避免重复定义。现在有两件事我想知道:

  1. 如何用例如

    替换(展开)每个for(;i; i < n)
    res[0] = x[0] + y[0];
    res[1] = x[1] + y[1];
    ...
    res[n] = x[n] + y[n];
    
  2. 将大量宏hackery导出到可读标头的简洁方法是什么?我应该在make文件中创建一个shell函数,将最终标题导出到include目录吗?

  3. 也许有更好的方法可以做到这一点。欢迎任何替代品。

1 个答案:

答案 0 :(得分:1)

以下是此answer使用these macro functions引用的一种可能解决方案:

# our DBFactory component, from some model package
class DBFactory(object):

    def __init__(self, db_url, **kwargs):
        db_echo = kwargs.get('db_echo', False)
        self.engine = create_engine(db_url, echo=db_echo)

        self.DBSession = sessionmaker(autoflush=False)
        self.DBSession.configure(bind=self.engine)
        self.metadata = Base.metadata
        self.metadata.bind = self.engine

    def get_session(self):
        session = self.DBSession()
        return session


# we instantiate them in the __init__.py file, and save on registry
def main(global_config, **settings):
    """runs on server start, returns a Pyramid WSGI application  """

    config = Configurator(
        settings=settings,
        # ask for a custom request factory
        request_factory = MyRequest,
    )

    config.registry.db1_factory = DBFactory( db_url=settings['db_1_url'] )
    config.registry.db2_factory = DBFactory( db_url=settings['db_2_url'] )


# and our custom request class, probably in another file
class MyRequest(Request):
    "override the pyramid request object to add explicit db session handling"

    @reify
    def db1_session(self):
        "returns the db_session at start of request lifecycle"
        # register callback to close the session automatically after
        # everything else in request lifecycle is done
        self.add_finished_callback( self.close_dbs_1 )
        return self.registry.db1_factory.get_session()

    @reify
    def db2_session(self):
        self.add_finished_callback( self.close_dbs_2 )
        return self.registry.db2_factory.get_session()

    def close_dbs_1(self, request):
        request.db1_session.close()

    def close_dbs_2(self, request):
        request.db2_session.close()


# now view code can be very simple    
def my_view(request):
    # get from db 1
    stuff = request.db1_session.query(Stuff).all()
    other_stuff = request.db2_session.query(OtherStuff).all()
    # the above sessions will be closed at end of request when 
    # pyramid calls your close methods on the Request Factory

    return Response("all done, no need to manually close sessions here!")

这是一个问题,但是以一种令人费解的,hacky,丑陋的方式......特别是,使用递归宏来进行迭代操作。