2015-07-04 11 views
24

Mam strukturę następująco:nietrywialne wyznaczone inicjalizatory nieobsługiwane

struct app_data 
{ 
    int port; 
    int ib_port; 
    unsigned size; 
    int tx_depth; 
    int sockfd; 
    char *servername; 
    struct ib_connection local_connection; 
    struct ib_connection *remote_connection; 
    struct ibv_device *ib_dev; 

}; 

Kiedy próbuję go zainicjować w następujący sposób:

struct app_data data = 
{ 
    .port = 18515, 
    .ib_port = 1, 
    .size = 65536, 
    .tx_depth = 100, 
    .sockfd = -1, 
    .servername = NULL, 
    .remote_connection = NULL, 
    .ib_dev = NULL 
}; 

otrzymuję ten błąd:

sorry, unimplemented: non-trivial designated initializers not supported 

Myślę, że chce kolejność inicjalizacji dokładnie tak, jak jest zadeklarowana i brakuje local_connection. Nie muszę go jednak inicjować, a ustawienie NULL nie działa.

Jeśli zmienię go do tego na g ++, wciąż ten sam błąd:

struct app_data data = 
{ 
    port : 18515, 
    ib_port : 1, 
    size : 65536, 
    tx_depth : 100, 
    sockfd : -1, 
    servername : NULL, 
    remote_connection : NULL, 
    ib_dev : NULL 
}; 
+0

Myślę, że używasz g ++ do kompilacji tego kodu. Jeśli tak, usuń "." Oznacza to, że .port staje się portem, .ib_port staje się ib_port. Powinien się później skompilować. – Anon

+1

Używam g ++ 4.9.2 (z włączonym C++ 11), ale usunięcie. nie działa? "port nie został zadeklarowany w tym zakresie" – Ivan

+0

Oh. Nie pamiętam, użyj ":" zamiast "=" np. port: 18515 i zrób to także dla innych zmiennych. – Anon

Odpowiedz

14

to nie działa z g ++. Zasadniczo używacie konstruktów C z C++. Kilka sposobów na obejście tego.

1) Usuń "." i podczas inicjowania zmień "=" na ":".

#include <iostream> 

using namespace std; 
struct ib_connection 
    { 
    int x; 
    }; 

    struct ibv_device 
    { 
    int y; 
    }; 

struct app_data 
{ 
    int port; 
    int ib_port; 
    unsigned size; 
    int tx_depth; 
    int sockfd; 
    char *servername; 
    struct ib_connection local_connection; 
    struct ib_connection *remote_connection; 
    struct ibv_device *ib_dev; 

}; 

int main() 
{ 

    struct app_data data = 
    { 
     port : 18515, 
     ib_port : 1, 
     size : 65536, 
     tx_depth : 100, 
     sockfd : -1, 
     servername : NULL, 

     local_connection : {5}, 
     remote_connection : NULL, 
     ib_dev : NULL 
    }; 

    cout << "Hello World" << endl; 

    return 0; 
} 

2) Użyj g ++ -X c. (Niezalecane) lub umieść ten kod w zewnętrznym C [Zastrzeżenie, tego nie przetestowałem]

+0

Należy również zauważyć, że ten kod nie jest przenośny (ale będzie działać z g ++). Z jakiego powodu używasz konstruktów C z C++? Robisz implementację jądra/sterownika? – Anon

+3

Dzięki, że działa. BTW, kropki działają w C++. Nie wiem, dlaczego zamiast tego zasugerowałeś ":". Jeśli chodzi o użycie C, to głównie mam przykłady, które są w C i próbuję przenieść je do C++. Jedna rzecz na raz. – Ivan

+0

@Ivan Dzięki, +1 dla Ciebie. Nie wiedziałem tego. Wypróbowałem ".port = 6000" i zadziałało! – Anon

-1

Należy również zauważyć, że zgodnie z pierwotnym pytaniem, kolejność wyrażeń członków ma znaczenie. Zauważyłem, że jeśli chciałbym zainicjować tylko "rozmiar" w poprzednim przykładzie, muszę umieścić wyrażenia dla .port i .ib_port wcześniej. W przeciwnym razie pojawia się błąd "przepraszam, niezatwierdzony: nietrywialne oznaczane inicjalizatory nieobsługiwane" Nie tak intuicyjne ...

+0

Jest to komentarz do odpowiedzi, a nie odpowiedzi na problem pytającego. – toonice

3

Zauważyłem, że mój kompilator GCC ma jakąś sztuczkę, aby zaakceptować .fieldname = przypisania wartości, ale będzie kompilował tylko jeśli pola przychodzą w tej samej kolejności, w jakiej są zadeklarowane w strukturze.

Udało mi się zainicjować tę strukturę na dwa sposoby. Ten z nazwami poprawia czytelność i redukuje ryzyko przypisania błędnych danych, jeśli kolejność pól strukturalnych zostanie później zmieniona.

//Declare struct 
typedef struct 
{ 
    uint32_t const * p_start_addr; 
    uint32_t const * p_end_addr; 
    fs_cb_t const callback;  
    uint8_t const num_pages; 
    uint8_t const priority; 
} fs_config_t; 

//Assign unnamed 
fs_config_t fs_config 
{ 
    (uint32_t*)0x00030000, // uint32_t const * p_start_addr; 
    (uint32_t*)0x00038000, // uint32_t const * p_end_addr;   
    fs_evt_handler,   // fs_cb_t const callback; 
    8,      // uint8_t const num_pages; 
    0xFE     // uint8_t const priority;    
}; 

//Assign to named fields 
static fs_config_t fs_config1 
{ 
    .p_start_addr = (uint32_t*)0x00030000, 
    .p_end_addr = (uint32_t*)0x00038000,    
    .callback = fs_evt_handler, 
    .num_pages = 8, 
    .priority = 0xFE     
};  

Zasadą jest:

  1. Przypisanie do .name = pola Wartość
  2. Przypisywanie w kolejności ich gdzie deklarowanej
  3. Uwzględnij wszystkie pola w assigment
9

kolejność inicjowania musi być w dokładnej kolejności deklaracji.

typedef struct FOO 
{ 
    int a; 
    int b; 
    int c; 
}FOO; 

FOO foo = {.a = 1, .b = 2}; // OK 
FOO foo1 = {.a = 1};   // OK 
FOO foo2 = {.b = 2, .a = 1}; // Error sorry, unimplemented: non-trivial designated initializers not supported 
FOO foo3 = {.a = 1, .c = 2}; // Error sorry, unimplemented: non-trivial designated initializers not supported 

Rozumiem, że oznacza to, że kompilator nie obsługuje obsługi zorientowanej na nazwę, poza kolejnością, inicjowania członków.

Konieczność zainicjowania struktury w staroświecki sposób. Zachowuję nazwy zmiennych dla jasności, ale muszę je zainicjować w kolejności i nie pomijać zmiennej.

Mogę zatrzymać inicjalizację przy dowolnej zmiennej, ale nie mogę zainicjować zmiennych, które z niej pochodzą.

+1

W przeciwieństwie do stwierdzenia przyjętej odpowiedzi, że to nie działa w g ++, z powodzeniem używam g ++ (5.3.0) z rozwiązaniem podanym w tej odpowiedzi (i nie używając "-X"). –

+0

Ta odpowiedź zadziałała. Mogłem zainicjować nazwę pola, ale musiałem to zrobić w kolejności, w której je zadeklarowałem. – alc6379

0

Niestety, C++ nie obsługuje wyznaczonych inicjatorów. GCC nadal pozwala używać ich (jako rozszerzenia), ale musisz zainicjować członków w tej samej kolejności, w jakiej są one wymienione w struct.

Innym rozwiązaniem jest użycie natychmiast powołać lambda:

constexpr fuse_operations fuse_ops = []{ 
    fuse_operations ops{}; 
    ops.destroy = wiifs_destroy; 
    ops.getattr = wiifs_getattr; 
    ops.access = wiifs_access; 
    // ... 
    return ops; 
}(); 

ja osobiście wolę to rozwiązanie, ponieważ jest doskonale standard C++, pozwala zainicjować pól w żądanej kolejności, pomiń te don” t potrzeba i domyślnie zainicjuj resztę. A kompilator nadal jest able to optimise this. Zauważ, że działa to tylko z C++ 17 lub nowszym.

Powiązane problemy