programing

C Macro - 정수 값을 문자열 리터럴로 가져오는 방법

powerit 2023. 11. 4. 13:20
반응형

C Macro - 정수 값을 문자열 리터럴로 가져오는 방법

GCC(AVR Studio)의 어셈블리 섹션의 일부인 문자열 리터럴에 #정의 정수 기호를 삽입할 값을 얻을 수 있습니까?

아래 asm() 블록 안에 있는 문자열 리터럴 안에 있는 "LED"를 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
...
}

지금까지 제가 생각할 수 있는 모든 매크로 트릭(#스트링, arg 치환, 심지어 #값과 큰따옴표의 다양한 조합을 가진 파일 포함)을 시도했습니다.

저는 AVR 스튜디오의 GCC 컴파일러에 AVR 어셈블리 코드를 입력하는 마법에 전혀 익숙하지 않습니다.

저는 제 소스에 "48" 리터럴이 여러 번 발생하는 것을 피하려고 합니다. 만약 전처리기가 저를 대신해서 이런 대체 작업을 수행할 수 있다면 좋을 것입니다.

편집: 마이크로컨트롤러 펌웨어 프로젝트를 위한 것입니다. 삶을 재미있게 만들기 위해 새로운 코드를 추가할 여유 공간이 거의 없습니다.

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

인접한 문자열 리터럴이 연결된다는 사실에 의존합니다.


다른 방법으로, 당신은 다음과 같이 만들 수 있습니다.STR쉼표에 관대한 매크로:

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

그리고 전체를 끈으로 묶는 겁니다asm다음과 같은 차체:

asm( STR(
    ldi        R27, 0x00;
    ldi        R26, 0x00;
    ldi        R18, LEDS; //LEDS gets expanded
)); //renders: "ldi R27, 0x00; ldi R26, 0x00; ldi R18, 48;"

(개인적으로 명시적인 문자열 리터럴보다 편리하다고 생각하여 clang/gcc/tinycc에 이렇게 글을 씁니다.)이 접근 방식은 조립품이 단지 하나의 라인일 뿐이며 조립자가 또한 수용하는 한 조립될 것이라는 잠재적인 단점을 가지고 있습니다.;새로운 라인과 더불어 명령어 구분자로서(적어도 clang/gcc/ tinycc의 x86-64 어셈블리에 대해 작동).

제약 조건을 사용하는 경우 문자열화 매크로가 발생하지 않도록 할 수 있습니다.

#define LEDS 48

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

이것이 작동하려면 보조 매크로가 두 개 필요합니다.그러면 자동 문자열 연결을 이용할 수 있습니다.

#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");

EXPANDmacro를 사용하면 전달된 매개 변수도 대체할 수 있습니다.

그럼 다음은.

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

다음으로 확장:

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

언급URL : https://stackoverflow.com/questions/40591312/c-macro-how-to-get-an-integer-value-into-a-string-literal

반응형