PROGMEM에서 배열 대신 포인터를 사용할 수없는 이유는 무엇입니까?


11

현재 프로젝트에서 SRAM이 부족하지 않도록 문자열 저장소에 RAM 대신 플래시를 사용하도록 일부 라이브러리를 변경하고 있습니다.

라이브러리의 일부 문자열은 다음과 같이 선언됩니다.

const char *testStringA = "ABC";

이것은 내가 정상적으로 수행하는 방식과 다릅니다.

const char testStringB[] = "DEF";

그러나 const 선언하고 선언에서 초기화 할 때이 두 가지는 동일하다고 생각합니다. 둘 다 코드에서 잘 작동합니다.

나는 이것을 플래시로 옮기려고 시도했다.

const prog_char *testStringC PROGMEM = "GHI";

나는 이것이 작동하지 않는 것을 발견했다. 인쇄 할 때 고 블럭을 생산하고있었습니다.

그러나 다음과 같은 일반적인 패턴을 따르십시오.

const prog_char testStringD[] PROGMEM = "JKL";

잘 작동합니다.

분해에서 볼 수 있습니다.

00000068 <testStringC>:
  68:   04 01                                               ..

0000006a <_ZL11testStringD>:
  6a:   4a 4b 4c 00                                         JKL.

따라서 포인터가 명확하고 PROGMEM으로 인해 문자열 / 배열이 초기화되지 않습니다.

왜 이런거야?

예제 코드 :

#include <avr/pgmspace.h>

const int BUFFER_LEN = 20;

const char *testStringA = "ABC";
const char testStringB[] = "DEF";
const prog_char *testStringC PROGMEM = "GHI";
const prog_char testStringD[] PROGMEM = "JKL";

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    char buffer[BUFFER_LEN];

    Serial.println(testStringA);
    Serial.println(testStringB);

    strncpy_P(buffer, testStringC, BUFFER_LEN);
    Serial.println(buffer);

    strncpy_P(buffer, testStringD, BUFFER_LEN);
    Serial.println(buffer);

    delay(1000);

}

답변:


6

글쎄,이 질문은 스택 오버플로 질문 C : char pointer와 array의 차이점대한 답변 에서 현명하게 답변되었습니다 .

기본적으로 PROGMEM으로 선언 한 내용은

const prog_char testStringD[] PROGMEM = "JKL";

는 배열과 현재의 범위 스택에있는 배열의 요소, 즉 배열의 요소입니다. 반면 :

const prog_char* testStringC PROGMEM = "GHI";

메모리의 다른 곳에있을 수 있지만 PROGMEM 문자열로 선언되지 않은 상수 문자열에 대한 PROGMEM 포인터를 선언합니다.

내가 않았지만 하지 그 테스트,하지만 당신은 선언하는 시도해야합니다 :

const prog_char* testStringC PROGMEM = F("GHI");

PROGMEM 공간 내에서 지정된 문자열을 실제로 할당합니다. 나는 생각 이 아두 이노의 사용, 작동해야 F()매크로 실제로 배열 선언과 같은 결과를 가지고에 상용구 코드를 많이 추가합니다.

주석에서 말했듯이 전역 컨텍스트가 PSTR()아닌 경우 F()매크로 대신 매크로를 사용할 수 있습니다 .

포인터 선언이 아닌 배열 선언을 사용하십시오!

Cf 다른 답변 , __flash한정자는 세 번째 솔루션입니다 ;-)


나는 배열이 훨씬 더 명확할수록 "단순할수록 좋다"는 것에 완전히 동의한다. 뭔가 분명하지 않을 때는 항상 관심을 갖습니다.
Cybergibbons

F ()는 본질적으로 동일한 FlashStringHelper를 반환하지만 PSTR ()을 사용하면 const가 함수 안에 포함되는 한 제대로 작동합니다.
Cybergibbons

실제로, 나는 먼저 PSTR()매크로를 제안 했지만 F()제출 하기 전에로 변경했습니다 . 왜냐하면 당신의 const는 Q의 전역 요소이므로 두 컨텍스트 모두에서 작동하는 것을 고수하는 것을 선호했습니다.
zmo

3

이 라인은 :

const prog_char *testStringC PROGMEM = "GHI";

문자열의 문자를 SRAM에 복사하기 위해 프롤로그 코드를 작성한 다음 플래시에 저장된 포인터 를이 SRAM 위치 로 초기화합니다 . 일반적인 방법으로 포인터를로드 한 다음 평소대로 포인터를 참조 해제해야합니다.

const char *str = pgm_read_word(&testStringC);
Serial.println(str);

이 줄 :

const prog_char testStringD[] PROGMEM = "JKL";

플래시 로 문자 배열을 만들어 예상대로 액세스 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.