Sự cần thiết của dấu ngoặc rỗng '{}' ở cuối chuỗi cấu trúc là gì?


59

Tôi nhấn một số trong nhân Linux:

static struct ctl_table ip_ct_sysctl_table[] = {
    {
        .procname   = "ip_conntrack_max",
        .maxlen     = sizeof(int),
        .mode       = 0644,
        .proc_handler   = proc_dointvec,
    },
    // ...
    {
        .procname   = "ip_conntrack_log_invalid",
        .maxlen     = sizeof(unsigned int),
        .mode       = 0644,
        .proc_handler   = proc_dointvec_minmax,
        .extra1     = &log_invalid_proto_min,
        .extra2     = &log_invalid_proto_max,
    },
    { }
};

Ở đây một mảng các kết cấu kết thúc với { }. Vì mục đích gì đã được thêm vào?
Nhân tiện, một chút trên mã này có một mảng các cấu trúc khác , nhưng không có dấu ngoặc rỗng ở cuối.

Khi nào tôi nên sử dụng niềng răng trống ở cuối một chuỗi các cấu trúc?


1
Hmm, nếu nó được thêm vào để báo hiệu kết thúc của mảng như 0 báo hiệu kết thúc chuỗi thì sao? Chỉ cần đoán.
Eraklon

4
Đây là một số phần mở rộng GCC không chuẩn. Và như vậy, rất có thể nó đi kèm với rất ít hoặc không có tài liệu ... Tôi chỉ đọc tất cả các tài liệu và tôi không thể tìm thấy bất cứ điều gì về danh sách trình khởi tạo cấu trúc trống. Tuy nhiên, nó biên dịch, trừ khi bạn buộc ISO nghiêm ngặt -pedantic.
Lundin

9
Dù sao, nó là một giá trị "sentinel", một mục với mọi thứ được đặt thành zero / NULL để đánh dấu sự kết thúc của mảng.
Lundin

Sentinels cũng phổ biến trong các mô-đun mở rộng CPython .
MaxPowers

Câu trả lời:


38

Sự thay đổi đặc biệt này là một phần của mạng lưới sysctl: Hủy bỏ không sử dụng đang sysctl nhị phân cam kết bởi Eric W. Biederman, thay đổi khởi tạo của phần tử cuối cùng của ip_ct_sysctl_tablemảng từ {0}đến {}(và thực hiện những thay đổi tương tự như nhiều khởi tạo mảng khác).

Các {0}mẫu dường như đã được khoảng lâu hơn nữa mặc dù, và cả hai {0}hoặc {}thức yếu tố-khởi là thường (trong mã nguồn Linux) một cách rõ ràng được gọi là Terminating entry, vì vậy nó có thể là một mô hình hiện tại để cho phép việc tiêu thụ những mảng mà không biết độ dài của họ, chấm dứt tiêu thụ khi nhấn vào mục kết thúc khởi tạo bằng không. Ví dụ: đối với các mảng tương tự trong sound/aoa/fabrics/snd-aoa-fabric-layout.cý định khởi tạo 0 thậm chí được đề cập rõ ràng trong một nhận xét, ví dụ:

static struct codec_connection toonie_connections[] = {
  {
      .connected = CC_SPEAKERS | CC_HEADPHONE,
      .codec_bit = 0,
  },
  {} /* terminate array by .connected == 0 */
};

11
Sẽ rất thú vị khi biết lý do của họ về việc bỏ tiêu chuẩn C để ủng hộ một phần mở rộng GCC tương đương 100% về chức năng. Tất cả những gì nó làm là ngăn chặn mã biên dịch trên trình biên dịch C tiêu chuẩn. Đó là, được cho là tương đương 100% vì gcc dường như không ghi lại tính năng này ... Đây không phải là một mảng có độ dài bằng không, nó là một danh sách khởi tạo trống.
Lundin

@Lundin Sẽ không int arr[] = {}(cho rằng chúng tôi đang sử dụng phần mở rộng khởi tạo trống GNU) dẫn đến một mảng trống; tức là kích thước của bản arrthể 0?
dfri

1
@Lundin: Tuy nhiên, trang cppreference mâu thuẫn với cách diễn đạt của ISO / IEC 9899: 2011, cho phép điều đó (§6.7.9 (21)). Không có trình khởi tạo nào chắc chắn là "ít" hơn các thành viên của tổng hợp. Vì vậy, đó không phải là một phần mở rộng trình biên dịch queer, mà là hợp pháp C.
Damon

2
@Damon Nó không hợp lệ C và nó nổi tiếng ... biên dịch với lỗi gcc -pedantic-. Để hiểu lý do tại sao, bạn cần đọc cú pháp thực tế cho danh sách trình khởi tạo, đầu trang 6.7.9. Phải có ít nhất một bộ khởi tạo. Giải thích tại đây: stackoverflow.com/questions/17589533/ . Cụ thể { initializer-list }sau đó danh sách khởi tạo: designation(opt) initializerhoặcinitializer-list , designation(opt) initializer
Lundin

2
@Lundin Trong trường hợp cụ thể này, không có ý tưởng. Nhưng phần mở rộng gcc được sử dụng rộng rãi trong kernel linux.
bobsburner

20

Bạn có thể quen thuộc với các chuỗi kết thúc bằng không. ctl_table ip_ct_sysctl_table[]là một mảng kết thúc bằng không, tức là mục mảng cuối cùng có tất cả các thành viên không.


1
Vì vậy, đi qua mảng, bạn biết bạn đã đạt đến cuối khi eg procnamelà null hoặc maxlenbằng không.
Paul Ogilvie

1
@PaulOgilvie: Chà, ví dụ không đầy đủ. procnamecó thể là char[100]trong trường hợp đó "", không phải là null. Nhưng nếu không thì có.
MSalters

13

Sự cần thiết của dấu ngoặc rỗng '{}' ở cuối chuỗi cấu trúc là gì?

Để được rõ ràng: các "dấu ngoặc vuông trống '{}' ở phần cuối của mảng của cấu trúc" không cần thiết để yêu cầu thỏa mãn C cú pháp.

Khi nào tôi nên sử dụng niềng răng trống ở cuối một chuỗi các cấu trúc?

Khi mã muốn một giá trị sentinel .

Đôi khi nó hữu ích cho chương trình để có một phần tử mảng cuối cùng của tất cả các số không - chắc chắn để phát hiện kết thúc. Các nhu cầu xuất phát từ việc sử dụng các ứng dụng của mảng ctl_table ip_ct_sysctl_table[], không phải từ một nhu cầu ngôn ngữ C.


9

Đó là một phần tử khởi tạo bằng 0 ở cuối mảng để tăng số phần tử của mảng lên một.

Hãy xem xét bản demo nhỏ này:

#include <stdio.h>

struct Test
{
  int x;
  int y;
} arr[] =
{
    {1,2},
    {3,4},
//  {}
};

int main(void) {
    printf("%zu\n", sizeof(arr) / sizeof(arr[0]));
    return 0;
}

Kích thước của arrmảng sẽ thay đổi nếu bạn bỏ ghi chú {}ở cuối danh sách khởi tạo mảng.

Đầu ra:

Với // {}(mảng có 2 phần tử)

2

Với {}(mảng có 3 phần tử)

3

Giải thích thêm:

Các ip_ct_sysctl_tablemảng chỉ được sử dụng tại một nơi, đó là ở đây:

in->ctl_table = kmemdup(ip_ct_sysctl_table,
                sizeof(ip_ct_sysctl_table),
                GFP_KERNEL);

Việc {}tăng thêm tổng kích thước ip_ct_sysctl_table.


1
Đó không phải là "để tăng số lượng phần tử của mảng" mà là để báo hiệu sự kết thúc của mảng.
Paul Ogilvie

6
LOL, không. Ý tưởng là cho đến nay không ai có thể giải thích nó hoàn toàn, với sự chắc chắn tuyệt đối. Tuyên bố gần nhất về sự chắc chắn chỉ đơn giản { }là cái khởi tạo. Nhưng tại sao vẫn chưa rõ ràng. Vì vậy, bây giờ dù sao đi nữa, từ này có lẽ là một ý tưởng tốt. :)
ryyker
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.