Khởi tạo mảng cấu trúc
Tôi đã tự định nghĩa cho mình một cấu trúc:
typedef struct {
unsigned char current;
unsigned char start;
unsigned char target;
unsigned long startTime;
unsigned int duration;
} led;
Tôi đã có thể khởi tạo một phiên bản như thế này:
led h_red = {0,0,255,0,300};
Tuy nhiên, khi tôi cố gắng có chúng trong một mảng:
led leds[LEDS];
leds[0] = {0,0,0,0,0};
leds[1] = {0,0,0,0,0};
leds[2] = {0,0,255,0,300};
Tôi gặp lỗi này
signal:28:1: error: 'leds' does not name a type
leds[0] = {0,0,0,0,0};
^~~~
signal:29:1: error: 'leds' does not name a type
leds[1] = {0,0,0,0,0};
^~~~
signal:30:1: error: 'leds' does not name a type
leds[2] = {0,0,255,0,300};
^~~~
Và tôi không biết mình đang làm gì sai ở đây. Bạn có thể xem toàn bộ thay đổi tại đây trên GitHub
Trả lời
led h_red = {0,0,255,0,300};
Ở đây, bạn đang xác định một biến và đồng thời cung cấp cho nó một giá trị ban đầu. Đây được gọi là khởi tạo .
led leds[LEDS];
Ở đây bạn đang xác định một mảng. Vì nó nằm trong phạm vi toàn cục và không được khởi tạo rõ ràng, nó được khởi tạo ngầm định cho tất cả các byte bằng không.
leds[0] = {0,0,0,0,0};
Ở đây, bạn đang cố gắng cung cấp giá trị cho một phần tử của mảng đã được xác định trước đó. Do đó, đây không phải là một khởi tạo, mà là một phép gán . Không giống như khởi tạo, phép gán không thể tồn tại bên ngoài một hàm. Nếu bạn muốn gán các giá trị ban đầu, bạn có thể thực hiện nó trong setup().
Ngoài ra, bạn có thể khởi tạo mảng trong khi bạn xác định nó:
led leds[LEDS] = {
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 255, 0, 300}
};
Tôi đã ủng hộ câu trả lời của @Edgar Bonet , vì nó đúng.
Tuy nhiên, tôi muốn thêm một số ví dụ và giải thích.
Tóm tắt chính:
Trong C và C ++, bạn KHÔNG thể có logic mã bên ngoài các hàm. Bên ngoài bối cảnh toàn cầu của các chức năng được thiết kế để khai báo , định nghĩa , và một số khởi tạo / nhà thầu duy nhất. Tất cả logic mã phải nằm bên trong một hàm . Logic mã bao gồm các phép gán biến sau xây dựng, các ifcâu lệnh, v.v.
Ví dụ:
1. KHÔNG được phép:
Do đó, bạn KHÔNG thể làm như sau, vì nó cố gắng thực hiện các nhiệm vụ không khởi tạo bên ngoài tất cả các phạm vi chức năng.
Cũng lưu ý rằng trong C ++ (là Arduino), bạn cũng không cần sử dụng typedefcho cấu trúc, vì vậy tôi đã xóa nó khỏi structđịnh nghĩa. Tôi cũng đang sử dụng các kiểu stdint.h , được coi là an toàn hơn và là "phương pháp hay nhất" cho các kiểu dữ liệu, vì chúng chỉ định kích thước kiểu chính xác tính bằng bit. Sử dụng uint8_tthay cho unsigned char, uint32_tthay vì Uno của Arduino unsigned long, và uint16_tthay vì Uno của Arduino unsigned int. Ngoài ra, trong C ++ nói riêng, constexprhay enums được ưu tiên hơn #defineđể đặt các hằng số biến.
constexpr uint8_t NUM_LEDS = 3;
struct Led {
uint8_t current;
uint8_t start;
uint8_t target;
uint32_t startTime;
uint16_t duration;
};
Led leds[NUM_LEDS];
// NOT OK: Variable (re)assignments are NOT allowed outside of functions in
// C and C++.
leds[0] = {0, 0, 0, 0, 0};
leds[1] = {0, 0, 0, 0, 0};
leds[2] = {0, 0, 255, 0, 300};
void setup()
{
}
void loop()
{
}
2. ĐƯỢC cho phép:
Tuy nhiên, bạn CÓ THỂ có các khởi tạo biến bên ngoài các hàm, miễn là chúng xảy ra cùng lúc với quá trình xây dựng , vì vậy điều này hoàn toàn hợp lệ:
Led leds[NUM_LEDS];
// This form of aggregate initialization during construction is just fine in the
// global scope outside of all functions.
Led leds[NUM_LEDS] = {
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 255, 0, 300},
};
void setup()
{
}
void loop()
{
}
3. Cũng được phép:
Hoặc, bạn có thể chỉ cần chuyển các nhiệm vụ lại của mình vào một hàm, chẳng hạn như setup():
Led leds[NUM_LEDS];
void setup()
{
// This variable (re)assignment is just fine since it's inside
// of a function.
leds[0] = {0, 0, 0, 0, 0};
leds[1] = {0, 0, 0, 0, 0};
leds[2] = {0, 0, 255, 0, 300};
}
void loop()
{
}
4. Ví dụ đầy đủ, chạy được trên PC:
Đây là một ví dụ đầy đủ, có thể chạy được trên PC, với tính năng in để xác minh nội dung của cấu trúc đã được thay đổi:
Tự chạy nó trực tuyến: https://onlinegdb.com/MnEOQgCQT.
#include <stdint.h>
#include <stdio.h>
// Get the number of elements in a C-style array
#define ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
constexpr uint8_t NUM_LEDS = 3;
struct Led {
uint8_t current;
uint8_t start;
uint8_t target;
uint32_t startTime;
uint16_t duration;
};
// To initialize once at construction. This form of aggregate initialization
// can be used anywhere: both inside and outside functions.
Led leds[NUM_LEDS] = {
{ 1, 2, 3, 4, 5},
{ 6, 7, 8, 9, 10},
{11, 12, 13, 14, 15},
};
// Print the full contents of an array of `Led` structs
void printLeds(const Led ledArrayIn[], size_t ledArrayLen)
{
for (size_t i = 0; i < ledArrayLen; i++)
{
printf("ledArrayIn[%lu]\n"
"current = %u\n"
"start = %u\n"
"target = %u\n"
"startTime = %u\n"
"duration = %u\n\n",
i,
ledArrayIn[i].current,
ledArrayIn[i].start,
ledArrayIn[i].target,
ledArrayIn[i].startTime,
ledArrayIn[i].duration);
}
}
int main()
{
printf("Hello World\n\n");
printLeds(leds, ARRAY_LEN(leds));
printf("==============\n\n");
// Do this to set or change the structs at any time AFTER construction!
// This variable (re)assignment is only allowed inside of a function, NOT
// in the global scope outside of all functions!
leds[0] = {10, 20, 30, 40, 50};
leds[1] = {60, 70, 80, 90, 100};
leds[2] = { 0, 0, 255, 0, 300};
printLeds(leds, ARRAY_LEN(leds));
return 0;
}
Đầu ra mẫu:
Hello World
ledArrayIn[0]
current = 1
start = 2
target = 3
startTime = 4
duration = 5
ledArrayIn[1]
current = 6
start = 7
target = 8
startTime = 9
duration = 10
ledArrayIn[2]
current = 11
start = 12
target = 13
startTime = 14
duration = 15
==============
ledArrayIn[0]
current = 10
start = 20
target = 30
startTime = 40
duration = 50
ledArrayIn[1]
current = 60
start = 70
target = 80
startTime = 90
duration = 100
ledArrayIn[2]
current = 0
start = 0
target = 255
startTime = 0
duration = 300
Các tài liệu tham khảo khác:
- https://en.cppreference.com/w/cpp/language/aggregate_initialization
- [câu trả lời của tôi] https://stackoverflow.com/questions/61240589/how-to-initialize-a-struct-to-0-in-c/61240590#61240590