簡體   English   中英

使用C ++預處理器定義多個相似的變量

[英]Define multiple similar variables with C++ preprocessor

單片機有許多引腳,每個引腳都定義為

const Leg PA29 { PIOA, BIT(29) };   // struct Pin is already taken
// ... about 120 more: 4 port x 32 pin

我寫了一個簡單的define ,使別名更短

#define P(Port,PinN)  \
    const Leg P##Port##PinN { PIO##Port, BIT(PinN) }

用作

P(D,2);  //produces PD2 with { PIOD, BIT(2) }

真好
現在,我需要為四個端口(每個端口有32個引腳)調用P 120+次。 我想看看

FOR_EACH( X in A,B,C,D ) \
  FOR_EACH( i in 0..31 ) \
    P(X,i);

請不要建議使用TCL,Python等來生成C ++代碼。
我找到了答案 ,但是要了解如何在我的情況下使用它會很復雜。

主要思想是避免復制粘貼120行。 所有120+引腳應定義為約10行。

更新。 BIT的定義方式:

///@param n is value from 0 to number of bits in unsigned value
template<typename UnsignedIntegerT=unsigned>
constexpr UnsignedIntegerT BIT(UnsignedIntegerT n){ return 1<<n; }

upd2。 最小的例子

///////////////////
// Vendor provides something like:
///////////////////

struct Pio
{
    unsigned reg1;
    unsigned reg2;
    unsigned reg3;
    //...
    unsigned regN;
};


// values not from datasheet but from lantern
#define PIOA  ((Pio*)0xAABB6789)
#define PIOB  ((Pio*)0xAABB2569)
#define PIOC  ((Pio*)0xAABB2566)
#define PIOD  ((Pio*)0xAABB2323)
//...



/////////////
// Kyb's code
/////////////

class Leg 
{
public:
    Pio *pio;
    unsigned pinN;
//methods...
};


///@param n is value from 0 to number of bits in unsigned value
template<typename UnsignedIntegerT=unsigned>
constexpr UnsignedIntegerT BIT(UnsignedIntegerT n){ return 1u<<n; }


//////////////
// Now need to define 120+ pins-legs

// like this
const Leg PA29 { PIOA, BIT(29) };

// or with shortener alias

/// Alias to shortly produce leg definition
/// Example: `P(A,2)` will define `PA2` with proper PIO and bit.
#define P(Port,PinN)  \
        const Leg P##Port##PinN { PIO##Port, BIT<unsigned>(PinN) }

//P(D,4);  //produces PD4
//P(C,3);

您沒有發布一個真正的最小示例。 因此,這充其量只是一個猜測。 但是,如果您使用的是C ++ 14,並且您的類型是constexpr可構造的,那么在我看來,您應該盡可能地避免使用預處理器,而應使用變量模板:

enum port {A, B, C, D};

template<port>
struct PIO_ID;
template<> struct PIO_ID<A>{ static constexpr auto value = PIOA; };
template<> struct PIO_ID<B>{ static constexpr auto value = PIOB; };
template<> struct PIO_ID<C>{ static constexpr auto value = PIOC; };
template<> struct PIO_ID<D>{ static constexpr auto value = PIOD; };

template<port P>
constexpr auto PIO = PIO_ID<P>::value;

template<port PORT, int PIN_NUM>
constexpr Leg P{ PIO<PORT> , BIT(PIN_NUM) };

就是這樣。 現在,您可以將這些常量稱為P<A, 0> ,依此類推。

您是否真的需要const Leg PA29 (大概在其他地方引用PA29 )?

如果您准備編寫PA[29]並且PA是具有合適的operator [] ,那么您將只需要定義PAPBPCPD (我可能甚至不使用預處理器)為此定義)。

另外, Boost Preprocessor庫提供了循環。

Boost預處理程序庫的解決方案:

#include "Pio.hpp"  // Has Leg and BIT definitions
#include "boost/preprocessor.hpp"  //#include "boost/preprocessor/iteration"


/// Alias to shortly produce leg definition
/// The P(A,2) will define PA2 with proper PIO and bit.
#define P(Port,PinN)  \
        const Leg P##Port##PinN { PIO##Port, BIT<unsigned>(PinN) }


#define PA(n)  P(A,n)
#define PB(n)  P(B,n)
#define PC(n)  P(C,n)
#define PD(n)  P(D,n)


#define BOOST_PP_LOCAL_MACRO(n)   PA(n);
#define BOOST_PP_LOCAL_LIMITS     (0, 31)
#include BOOST_PP_LOCAL_ITERATE()  //??=include BOOST_PP_LOCAL_ITERATE()  //-Wtrigraphs

#define BOOST_PP_LOCAL_MACRO(n)   PB(n);
#define BOOST_PP_LOCAL_LIMITS     (0, 31)
#include BOOST_PP_LOCAL_ITERATE()

#define BOOST_PP_LOCAL_MACRO(n)   PC(n);
#define BOOST_PP_LOCAL_LIMITS     (0, 31)
#include BOOST_PP_LOCAL_ITERATE()

#define BOOST_PP_LOCAL_MACRO(n)   PD(n);
#define BOOST_PP_LOCAL_LIMITS     (0, 31)
#include BOOST_PP_LOCAL_ITERATE()

這很好用。 但是帶來的不便之處在於:IDE將在PA5和其他符號下划線為未解決的符號。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM