Yapı dizisinin sonunda '{}' boş parantezlere ne gerek var?


59

Linux çekirdeğinde bazı kodlarına çarptım:

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,
    },
    { }
};

Burada bir dizi yapı ile biter { }. Hangi amaçla eklendi?
Bu arada, bu kodun biraz üstünde başka bir yapı dizisi var , ancak sonunda boş parantez yok.

Bir dizi dizinin sonunda ne zaman boş ayraç kullanmalıyım?


1
Hmm, dizinin sonuna 0 gibi sinyal dizesinin sonunu bildirmek için eklendiğinde ne olur? Sadece tahmin ediyorum.
Eraklon

4
Bu, bazı standart olmayan GCC uzantılarıdır. Ve bu nedenle, büyük olasılıkla çok az veya hiç belge ile birlikte geliyor ... Sadece tüm belgeleri okudum ve boş yapı başlatıcı listeleri hakkında hiçbir şey bulamıyorum. Ancak, katı ISO'yu zorlamadığınız sürece derler -pedantic.
Lundin

9
Her neyse, dizinin sonunu işaretlemek için her şeyi sıfır / NULL olarak ayarlanmış bir "sentinel" değeridir.
Lundin

Nöbetçiler ayrıca CPython genişletme modüllerinde yaygındır .
MaxPowers

Yanıtlar:


38

Bu özel değişim parçasıydı sysctl net: Kullanılmayan ikili sysctl kodu kaldırın son elemanın başlatma değişen Eric W. Beiderman tarafından taahhüt ip_ct_sysctl_tablegelen diziye {0}için {}(ve gerçekleştirir diğer birçok dizi başlatımlar benzer değişiklikler).

{0}Desen çok daha uzun olsa süredir var gibi görünüyor ve her iki {0}veya {}nihai eleman-başlatma açıkça olarak anılacaktır (Linux kaynak kodunda) genellikle olduğu Terminating entryonların uzunlukları bilmeden bu diziler tüketen izin vermek için bir model mevcut muhtemeldir yüzden, sıfır başlangıçlı sonlandırma girişine basarken tüketimi sonlandırma. Örneğin sound/aoa/fabrics/snd-aoa-fabric-layout.c, sıfır başlatma amacındaki benzer diziler için bir yorumda açıkça belirtilmiştir, örneğin:

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

11
İşlevsellik açısından% 100 eşdeğeri olan bir GCC uzantısı lehine standart C'yi bırakma gerekçelerini bilmek ilginç olacaktır. Tek yaptığı, kodun standart C derleyicilerinde derlenmesini önlemektir. Olduğunu, güya% 100 eşdeğer gcc Bu ... Bu özelliği belgelemek görünmüyor çünkü değil boş bir başlatıcı listesi, sıfır uzunlukta dizi.
Lundin

@Lundin int arr[] = {}(GNU boş başlatıcı uzantısını kullandığımız göz önüne alındığında) boş bir diziyle sonuçlanmaz; yani arrvarlık büyüklüğü 0?
dfri

1
@Lundin: Cppreference sayfası, buna izin veren ISO / IEC 9899: 2011 ifadeleriyle çakışıyor (§6.7.9 (21)). Hiçbir başlatıcı, şüphesiz toplamın üyelerinden "daha az" değildir. Yani bu bir queer derleyici uzantısı değil, meşru C.
Damon

2
@Damon Geçerli C değil ve iyi bilinen ... gcc -pedantic-hataları ile derleyin. Nedenini anlamak için, bir başlatıcı listesi için 6.7.9'un üstündeki gerçek sözdizimini okumalısınız. En az bir başlatıcı olmalıdır. Burada açıklanmıştır: stackoverflow.com/questions/17589533/… . Daha { initializer-list }sonra başlatıcı listesi: designation(opt) initializerveyainitializer-list , designation(opt) initializer
Lundin

2
@Lundin Bu özel örnekte hiçbir fikrim yok. Ancak gcc uzantıları linux çekirdeğinde yaygın olarak kullanılmaktadır.
bobsburner

20

Muhtemelen sıfır sonlu dizeleri biliyorsunuzdur. ctl_table ip_ct_sysctl_table[]sıfır sonlu bir dizidir, yani son dizi girdisinin tamamen sıfır üyesi vardır.


1
Yani dizi boyunca, örneğin procnamenull veya maxlensıfır olduğunda sona ulaştığını biliyorsunuz .
Paul Ogilvie

1
@PaulOgilvie: Örnek eksik. procnamebir char[100]durumda olabilir "", boş değil. Ama aksi halde evet.
MSalters

13

Yapı dizisinin sonunda '{}' boş parantezlere ne gerek var?

Açık olmak gerekirse: C sözdizimi gereksinimlerini karşılamak için "yapı dizisinin sonundaki" boş ayraçlar "{} ' gerekli değildir .

Bir dizi dizinin sonunda ne zaman boş ayraç kullanmalıyım?

Kod bir sentinel değeri istediğinde .

Bazen programın tüm sıfırların son bir dizi öğesine sahip olması yararlı olur - kesinlikle sonu tespit etmek. Gerek dizinin uygulamanın kullanımı geliyor ctl_table ip_ct_sysctl_table[]değil C dili ihtiyaçtan.


9

Dizinin eleman sayısını bir arttırmak için dizinin sonunda sıfır olarak sıfırlanmış bir öğedir.

Bu küçük demosu düşünün:

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

Dizi başlatma listesinin sonundaki arrişareti kaldırırsanız dizinin boyutu değişecektir {}.

Çıktılar:

İle // {}(dizinin 2 öğesi vardır)

2

İle {}(dizinin 3 öğesi vardır)

3

Daha fazla açıklama:

ip_ct_sysctl_tableDizi sadece burada tek bir yerde en kullanılır:

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

Ekstra {}toplam boyutu artırır ip_ct_sysctl_table.


1
Bu "dizinin eleman sayısını artırmak için" değil, dizinin sonunu işaret etmek içindir.
Paul Ogilvie

6
Haha hayır. Fikir şu ana kadar hiç kimsenin onu tam olarak, kesinlikle kesin olarak açıklayamadığıdır. Kesinlike en yakın ifade basitçe { }bir başlatıcı olmasıdır. Ama neden hala belirsiz. Bu nedenle, şimdilik , kelime muhtemelen muhtemelen iyi bir fikirdir. :)
ryyker
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.