Tại sao tôi không thể sử dụng con trỏ thay vì mảng với PROGMEM?


11

Tôi hiện đang thay đổi một số thư viện để sử dụng flash thay vì RAM để lưu trữ chuỗi để tôi không hết SRAM trong một dự án.

Một số chuỗi trong thư viện được khai báo theo cách này:

const char *testStringA = "ABC";

Điều này khác với cách tôi thường thấy điều này được thực hiện:

const char testStringB[] = "DEF";

Tuy nhiên, tôi nghĩ rằng hai cái này là tương đương khi khai báo const và khởi tạo trong khai báo. Cả hai đều hoạt động tốt trong mã.

Tôi đã cố gắng chuyển những thứ này sang flash:

const prog_char *testStringC PROGMEM = "GHI";

Sau đó tôi thấy rằng điều này đã không làm việc. Nó đã được sản xuất gobbledegook khi in.

Tuy nhiên, theo mô hình thông thường hơn của:

const prog_char testStringD[] PROGMEM = "JKL";

hoạt động tốt

Tôi có thể thấy trong phần tháo gỡ:

00000068 <testStringC>:
  68:   04 01                                               ..

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

Vì vậy, rõ ràng con trỏ và kết quả PROGMEM trong chuỗi / mảng không được khởi tạo.

Tại sao lại thế này?

Mã ví dụ:

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

}

Câu trả lời:


6

Vâng, câu hỏi này đã được trả lời một cách khôn ngoan trong câu trả lời cho câu hỏi Stack Overflow C: sự khác biệt giữa con trỏ char và mảng .

Về cơ bản, những gì bạn đang tuyên bố là PROGMEM với,

const prog_char testStringD[] PROGMEM = "JKL";

là cả mảng và bộ nhớ mà nó trỏ tới, nghĩa là các phần tử của mảng, cả trong ngăn xếp phạm vi hiện tại. Trong khi đó với:

const prog_char* testStringC PROGMEM = "GHI";

bạn khai báo một con trỏ PROGMEM thành một chuỗi không đổi có thể ở nơi khác trong bộ nhớ, nhưng không được khai báo là một chuỗi PROGMEM.

Mặc dù tôi không kiểm tra điều đó, nhưng bạn nên thử khai báo:

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

để thực sự phân bổ chuỗi nhọn trong không gian PROGMEM. Tôi đoán nó nên hoạt động, sử dụng F()macro của Arduino , bổ sung rất nhiều mã soạn sẵn để thực sự có kết quả giống như khai báo mảng.

Như đã nói trong các bình luận, nếu không phải trong bối cảnh toàn cầu, PSTR()macro có thể được sử dụng thay vì F()macro.

Đơn giản hơn: sử dụng khai báo mảng, không phải con trỏ một!

Cf rằng câu trả lời khác , các __flashvòng loại là một giải pháp thứ ba ;-)


Tôi hoàn toàn đồng ý về "đơn giản hơn là tốt hơn" - mảng rõ ràng hơn nhiều. Tôi chỉ luôn quan tâm khi một cái gì đó không rõ ràng ngay lập tức.
Cyberg Ribbon

F () trả về FlashStringHelper về cơ bản là giống nhau, nhưng sử dụng PSTR () hoạt động tốt (miễn là bạn mang các hằng số bên trong một hàm).
Cyberg Ribbon

thực vậy, tôi thực sự đã đề xuất PSTR()macro trước nhưng thay đổi thành F()trước khi gửi, bởi vì các hằng số của bạn là toàn cục trong Q của bạn, vì vậy tôi thích gắn bó với cái nên hoạt động trong cả hai bối cảnh.
zmo

3

Dòng này là gì:

const prog_char *testStringC PROGMEM = "GHI";

không phải là viết mã prologue để sao chép các ký tự trong chuỗi sang SRAM, và sau đó khởi tạo con trỏ được lưu trong flash tới vị trí SRAM này. Bạn phải tải con trỏ qua các phương tiện thông thường, và sau đó hủy bỏ con trỏ như bình thường.

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

Đường thẳng này:

const prog_char testStringD[] PROGMEM = "JKL";

tạo ra các mảng ký tự trong flash, cho phép bạn truy cập nó như mong đợi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.