2016-11-14 16 views
30

Czy jest możliwe uzyskanie wartości symbolu #defined integer do dosłownego wstawienia w literał łańcuchowy, który jest częścią sekcji złożenia w GCC (AVR Studio)?C Makro - jak uzyskać wartość całkowitą w ciągu literowym

Chcę, aby "LEDS" zostały zastąpione przez 48 w ciągu literału wewnątrz bloku asm() poniżej.

#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 
... 
} 

ale chcę kompilatora/asembler (po preprocesor zrobił to zadanie), aby zobaczyć ten ...

#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 
... 
} 

Do tej pory próbowałem wszystkie makro sztuczki mogę myśleć (#stringification, substytucja arg, a nawet #include pliki z różnymi kombinacjami wartości i podwójnych cudzysłowów i cokolwiek).

Nie jestem zaznajomiony z magią wprowadzania kodu zestawu AVR do kompilatora GCC AVR Studio.

Próbuję uniknąć wielu wystąpień literału "48" w moim źródle, jeśli preprocesor może wykonać to zastąpienie dla mnie, byłoby świetnie.

Edytuj: Jest to projekt oprogramowania układowego mikrokontrolera - i tylko po to, aby życie było interesujące, prawie nie ma wolnego miejsca na dodanie nowego kodu.

+0

przyjrzeć [Umieszczenie dyrektywę preprocesora wewnątrz łańcucha dosłownym] (http://stackoverflow.com/q/14721007/ 2305521) – fpg1503

+2

Dlaczego łańcuch i konkatenacja nie działają? –

+0

@CodyGray, stringification nie "ocenia" tego, co przekazujesz, po prostu pobiera znaki z argumentu i zrzuca je bezpośrednio vrbatim, chyba że użyjesz dodatkowego makra do zastąpienia pożądanych znaków przed stringyfikacją. – Wossname

Odpowiedz

46

myślę, że dobrze jest mieć makro stringifying w swoim utils header:

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

wtedy może zachować makro liczbowo i uszeregować go na miejscu:

#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" 
... 
} 

Powyższe preprocesses do:

int x = 48; 

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

, która polega na tym, że sąsiednie literały łańcuchowe uzyskać łączone.

+4

To jest lepsza wersja mojej odpowiedzi. Rewizja. – 2501

+0

Ahh, tak, wydaje się, że to wystarczy. Myślę, że miałem coś podobnego do tego, ale moje #defines były basowe. Wspaniały. – Wossname

13

Potrzebujesz dwóch pomocniczych makr, aby to działało. Następnie można skorzystać z automatycznego połączonego łańcucha znaków:

#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" 
... 
} 

Powodem pomocą dwóch makr jest to, że sam pierwszy nie poszerzy parametr przekazany w

Jeśli właśnie to zrobił.

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

byłoby rozszerzyć do tego:

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

EXPAND makro pozwala również na zastąpienie parametru.

Więc tak:

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

rozwinie się do tego:

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

Można uniknąć stringification makro bałagan jeśli używasz ograniczenia:

#define LEDS 48 

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

Interesujące. Ta strona wygląda na trafną: https://gc.gnu.org/onlinedocs/gcc/Extended-Asm.html. W tym przypadku będę trzymać się nieprzyjemnych makr, ponieważ jest to łatwiejsze do zrozumienia przez programistów C (rodzaj!). – Wossname

+2

@Wossname: W jaki sposób zamierzasz używać "podstawowego" asm (bez ograniczeń) bez wchodzenia na palce kompilatora (tzn. Bez blokowania rejestrów)? Więcej informacji można znaleźć w [wiki wbudowanego tagu montażowego] (http://stackoverflow.com/tags/inline-assembly/info). "Rozszerzony" asm to normalny sposób korzystania z niego, a AFAIK to jedyny bezpieczny sposób, aby zrobić więcej, niż użyć instrukcji, która nie wpływa na rejestry (np. Ogrodzenie pamięci lub coś takiego). –

+0

@PeterCordes, Używam tylko ASM, aby uzyskać niezbędne instrukcje wykonane w krytycznym okresie czasu. Jak tylko ASM wróci do kodu C, cała pamięć używana w ASM zostanie ponownie zainicjowana. Wyjście asemblera wskazuje, że w tym nie będzie problemu. Ale masz rację, podnosząc tę ​​kwestię, jeśli miałbym zwyczaj nawiązywać przy użyciu zestawu AVR (raczej nie jest to prawdopodobne), to z pewnością zajrzałbym do właściwego sposobu robienia rzeczy. W tej chwili najgorsze, co się stanie, to to, że moje święta przestaną migać przez kilka sekund. :) – Wossname

Powiązane problemy