2016-11-14 15 views
30

整数シンボルの値をGCC(AVR)のアセンブリセクションの一部である文字列リテラルに逐語的に挿入することは可能ですか?スタジオ)?Cマクロ - 文字列リテラルに整数値を取得する方法

以下のasm()ブロック内の文字列リテラル内で "LEDS"を48に置き換えたいとします。

#define LEDS 48 //I only want ONE mention of this number in the source 
int x = LEDS; //I'm using the value directly too 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, LEDS  \n\t" //<-- substitution needed here 
... 
} 

しかし、私はこれを見て(プリプロセッサが行われた後、それが仕事です)コンパイラ/アセンブラをしたい...

#define LEDS 48 //I only want ONE mention of this number in the source 
int x = LEDS; //I'm using the value directly too 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, 48   \n\t" //<-- substitution needed here 
... 
} 

これまでのところ、私は(私は考えることができるすべてのマクロのトリックを試してみました#stringification、argの置換、さらに値と二重引用符などのさまざまな組み合わせを含むファイルも含む)。

私はAVR StudioのGCCコンパイラにAVRアセンブリコードをインライン化する魔法に慣れていません。

プリプロセッサが私にこのような置換を実行することができれば、私のソースには "48"というリテラルが複数回現れるのを避けようとしています。

編集:これはマイクロコントローラのファームウェアプロジェクト用であり、人生を面白くするために、新しいコードを追加する余裕がほとんどありません。

+0

はhttp://stackoverflow.com/q/14721007/([文字列リテラル内のプリプロセッサディレクティブを配置する]を見てください2305521) – fpg1503

+2

文字列化と文字列連結が機能しないのはなぜですか? –

+0

@CodyGray、stringificationはあなたが渡したものを "評価"せず、文字列化の前に余分なマクロを使用しない限り、引数内の文字を単純にvrbatimから抜き出します。 – Wossname

答えて

46

を私はそれがあなたのutilsのヘッダに文字列化マクロを持って良いことだと思う:

#define STR_IMPL_(x) #x  //stringify argument 
#define STR(x) STR_IMPL_(x) //indirection to expand argument macros 

それからマクロ数値を保持し、現場で文字列化することができます:

#define LEDS 48 
int x = LEDS; 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, "STR(LEDS)"  \n\t" 
... 
} 

に上記の前処理:隣接する文字列リテラルが連結得るという事実に依存

int x = 48; 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, ""48""  \n\t" 
... 
} 

+4

これは私の答えのより良いバージョンです。 Upvoted。 – 2501

+0

ああ、はい、そのトリックを行うようです。私はこれに似た何かを持っていたと思うが、私の#definesは低音である。素晴らしい。 – Wossname

13

これを機能させるには、2つの補助マクロが必要です。その後、自動文字列の連結を利用することができます

#define STR(x) #x 
#define EXPAND(x) STR(x) 

#define LEDS 48 
int x = LEDS; 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, " EXPAND(LEDS) "  \n\t" 
... 
} 

理由を二つのマクロを使用するだけで最初は、渡されたパラメータを拡張しないであろうということです

あなたはこのやった場合:。

printf("LEDS = " STR(LEDS) "\n"); 

それは、これに拡大する:

printf("LEDS = " "LEDS" "\n"); 

EXPANDマクロで渡されたパラメータも同様に置換されます。

だから、この:

printf("LEDS = " EXPAND(LEDS) "\n"); 

たが、これに拡大する:

printf("LEDS = " "48" "\n"); 
14

あなたは制約を使用する場合は、文字列化マクロ混乱を避けることができます。

#define LEDS 48 

void DrawFrame() 
{ 
    asm volatile(
    "ldi R18, %[leds]" 
    : : [leds] "M" (LEDS) : "r18"); 
} 
+1

興味深い。このページは関連性があります:https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html。この例では、Cプログラマがより簡単に理解できるので、厄介なマクロを使用します(一種!)。 – Wossname

+2

@Wossname:コンパイラのつま先を踏んだり(言わずにレジスタを壊す)ことなく、 "制約なし"で "基本的な" asmをどのように使うつもりですか?詳細については、[インラインアセンブリタグwiki](http://stackoverflow.com/tags/inline-assembly/info)を参照してください。 "拡張" asmは通常の使用方法であり、AFAIKはレジスタに影響を与えない命令(メモリフェンスなど)を使用する以外に唯一の安全な方法です。 –

+0

@PeterCordes、私は重要な時間枠内で必要な指示を行うためにASMを使用しています。 ASMがCコードに戻るとすぐに、ASMで使用されるすべてのメモリが再初期化されます。アセンブラの出力は、これは問題ではないことを示しています。しかし、あなたがこの点を上げるのは正しいです、もし私がAVRアセンブリ(おそらくそうではない)を使用する習慣をつくるなら、私は確かに正しい方法を検討するでしょう。それが現れている最悪の事は、私のクリスマスツリーが数秒間点滅を止めるということです。 :) – Wossname

関連する問題