ทำไมฉันไม่สามารถใช้พอยน์เตอร์แทนการใช้อาเรย์กับ PROGMEM ได้?


11

ขณะนี้ฉันกำลังเปลี่ยนห้องสมุดบางแห่งให้ใช้แฟลชแทน RAM สำหรับการจัดเก็บสตริงเพื่อที่ฉันจะไม่หมด SRAM ในโครงการ

สตริงบางตัวในไลบรารีถูกประกาศในลักษณะนี้:

const char *testStringA = "ABC";

สิ่งนี้ต่างจากวิธีที่ฉันเห็นสิ่งนี้ตามปกติ:

const char testStringB[] = "DEF";

อย่างไรก็ตามฉันคิดว่าทั้งสองนี้เท่ากันเมื่อประกาศ const และเริ่มต้นในการประกาศ ทำงานได้ดีทั้งในรหัส

ฉันพยายามย้ายสิ่งเหล่านี้ไปยังแฟลช:

const prog_char *testStringC PROGMEM = "GHI";

ฉันพบว่ามันใช้งานไม่ได้ มันกำลังผลิต gobbledegook เมื่อพิมพ์

อย่างไรก็ตามทำตามรูปแบบปกติของ:

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: ความแตกต่างระหว่างตัวชี้ถ่านและอาเรย์

โดยพื้นฐานแล้วสิ่งที่คุณประกาศในฐานะ PROGMEM ด้วย

const prog_char testStringD[] PROGMEM = "JKL";

เป็นทั้งอาร์เรย์และหน่วยความจำที่ชี้ไปนั่นคือองค์ประกอบของอาร์เรย์ทั้งในขอบเขตสแต็กปัจจุบัน ในขณะที่:

const prog_char* testStringC PROGMEM = "GHI";

คุณประกาศตัวชี้ PROGMEM เป็นสายอักขระคงที่ที่อาจอยู่ที่อื่นในหน่วยความจำ แต่ไม่ประกาศเป็นสายอักขระ PROGMEM

แม้ว่าฉันไม่ได้ทดสอบสิ่งนั้น แต่คุณควรพยายามประกาศ:

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

เพื่อจัดสรรสตริงสปอตจริงภายในพื้นที่ PROGMEM ฉันคิดว่ามันควรจะทำงานได้โดยใช้F()มาโครของ Arduino ซึ่งเพิ่มรหัสสำเร็จรูปจำนวนมากเพื่อให้ได้ผลลัพธ์เดียวกันกับการประกาศอาร์เรย์

ดังที่ได้กล่าวไว้ในความคิดเห็นหากไม่ได้อยู่ในบริบทสากลPSTR()สามารถใช้F()แมโครแทนแมโครได้

ง่ายกว่าดีกว่า: ใช้การประกาศอาร์เรย์ไม่ใช่ตัวชี้!

ถ้าเป็นเช่นนั้นคำตอบอื่น ๆผู้__flashคัดเลือกคือโซลูชันที่สาม ;-)


ฉันเห็นด้วยอย่างยิ่งกับ "ง่ายกว่าดีกว่า" - อาเรย์นั้นชัดเจนกว่า ฉันสนใจเสมอเมื่อมีอะไรบางอย่างไม่ชัดเจนในทันที
Cybergibbons

F () ผลตอบแทน FlashStringHelper ซึ่งเป็นหลักเดียวกัน แต่ใช้ PSTR () ทำงานได้ดี (ตราบเท่าที่คุณนำ consts ภายในฟังก์ชั่น)
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.