logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Jak zarezerwować ciągły obszar pamięci dla struktury w C?

Ballbreaker 23 Sie 2010 11:33 1650 9
REKLAMA
  • #1 8428299
    Ballbreaker
    Poziom 12  
    Posty: 71
    Pomógł: 7
    Ocena: 1
    Witam !

    Mam sobie strukturę:

    struct xxx {
      int data1;
      void *pData2;
      char some_buffer[25];
    
      int (*doAction)(int, int);
    };


    i teraz: chcę zarezerwować pewną ilość miejsca, w samej strukturze, chodzi o to aby zarezerwowany obszar pamięci był ciągły i w wolnym miejscu tejże struktury, mogę wpisać inną strukturę. Np

    struct inner_structure {
      int from;
      int to;
    };
    
    struct outer_structure {
      int a1;
      double a2;
      struct inner_structure inner;
      // ...
      int (*doAction)(int, int);
    };


    W takim przypadku struktura inner_structure zajmie 8 bajtów (zależnie od implementacji inta na platformie) i to jest w porządku. Problem polega na tym, że w wolne pole chcę wpisywać dowolną strukturę na stałe. Mogę oczywiście dynamicznie zarezerwować odpowiednie miejsce gdzieś na stosie w stylu:
    
    struct outer_structure {
      struct inner_structure *inner
    }
    
    main()
    {
      outer_structure out;
      out.inner = (inner_structure*) malloc (sizeof(inner_structure))
    }



    Ale chodzi mi o to, abym w czasie tworzenia struktury zewnętrznej (i dopiero wtedy) zapodał parametr ile wolnej przestrzeni ma zostać w strukturze, na kolejne moje dane. Myślałem troche o polu unii, ale nie wchodzi ono w grę bo przestawiłoby mi drzewo zależności do góry nogami.

    Czy ktoś zna jakiś elegancki sposób wymuszenia rezerwacji pamięci dla struktury w ten sposób ?

    Pzdr!
  • REKLAMA
  • #2 8428339
    Dżyszla
    Poziom 42  
    Posty: 7075
    Pomógł: 1095
    Ocena: 224
    Nie ma takiej możliwości, aby podczas dynamicznego tworzenia struktury zawierającej wskaźniki, w niej wygospodarować miejsce. Każdy wskaźnik pozostanie tylko wskaźnikiem do innego obszaru pamięci. Albo statyczna struktura, albo dynamiczna z dopuszczeniem fragmentacji.
  • REKLAMA
  • #3 8428981
    szelus
    Poziom 34  
    Posty: 1508
    Pomógł: 315
    Ocena: 53
    W C rozmiar struktury jest zawsze stały. W C++ pewnego rodzaju rozwiązanie mogą stanowić klasy pochodne (ale też rozwiązanie statyczne). W C można co najwyżej zastosować pseudoobiektowość, tzn. zadeklarować wiele struktur z takim samymi danymi na początku (dane wspólne) i odpowiednio rzutować wskaźnik przy dostępie.
  • REKLAMA
  • #4 8429145
    Ballbreaker
    Poziom 12  
    Posty: 71
    Pomógł: 7
    Ocena: 1
    To fakt, mogę też zaalokować sobie ciągły blok pamięci, jeśli znam rozmiary wszystkich struktur np:

    struct inner_structure {
      int from;
      int to;
    };
    
    struct outer_structure {
      int a1;
      double a2;
      struct inner_structure *inner;
      // ...
      int (*doAction)(int, int);
    };
    
    
    main()
    {
      struct outer_structure *os;
      os = (outer_structure*) malloc (sizeof(outer_structure) + sizeof (inner_structure));
      
      os->inner = (inner_structure*)((char*)os + sizeof(outer_structure));
    }
    


    wtedy struktury układam sobie w pamięci jedna, po drugiej. Zwolnienie free(os) zwalnia obie struktury jednocześnie.

    Pozdr.
  • REKLAMA
  • Pomocny post
    #5 8431140
    Dr.Vee
    VIP Zasłużony dla elektroda
    Posty: 1784
    Pomógł: 307
    Ocena: 76
    Jest też taka "sztuczka" z alokacją tablicy na końcu struktury:
    
    struct varString {
        unsigned size;
        char string[1];
    };
    
    struct varString* alloc(unsigned size)
    {
        struct varString* vs = malloc(sizeof(struct varString + size - 1));
        vs->size = size;
        return vs;
    }


    Może Ci się kiedyś przyda :)

    Pozdrawiam,
    Dr.Vee
  • #6 8431982
    Ballbreaker
    Poziom 12  
    Posty: 71
    Pomógł: 7
    Ocena: 1
    Dzięki za pomocną uwagę :)

    Właściwie na końcu struktury to nie ma problemu, zawsze można coś tam zaimprowizować, natomiast bardziej interesujące jest wstawienie wolnej przestrzeni w samej strukturze. Nie ma z tym problemu, jeżeli znany jest rozmiar dziury z góry, natomiast jeżeli tak jak w moim przypadku mogą to być różne struktury, o różnej wielkości, to trzeba trochę zaimprowizować.

    Dzięki za pomysł.
    Każda sztuczka jest na wagę złota ;>

    HOWGH !
  • #7 8433376
    Dżyszla
    Poziom 42  
    Posty: 7075
    Pomógł: 1095
    Ocena: 224
    Myślałem, że zależy Ci na środku ;) O tym samym także myślałem, co Dr napisał. A powiedz - jaki masz cel w takim działaniu? Może by jakaś inna metoda się znalazła.
  • #8 8435743
    Ballbreaker
    Poziom 12  
    Posty: 71
    Pomógł: 7
    Ocena: 1
    Cel jest jeden: aby działało. :)
    Próbuję stworzyć niezależne od platformy klasy kontenerów (w czystym C) i stworzyć dla nich uniwersalny interfejs iteratora. Każdy kontener ma swój iterator, i podpina mu swoje metody pod uniwersalny interfejs (vtable) natomiast iterator nie wie nic o kontenerach i tak ma zostać. Problemem jest to, że dla każdego rodzaju kontenera (wektor, lista, mapa) iterator potrzebuje innego zestawu danych aby znać swoją pozycję w strukturze. Te dane są obsługiwane przez funkcje tworzone w kontenerze i przypisywane do vtable iteratora.

    Dlatego też tworząc iterator potrzebuję stworzyć miejsce na dane. Zależy mi na jak najmniejszej fragmentacji pamięci, bo pamięć trzeba szanować.
    Dane mają różną wielkość w zależności od rodzaju iteratora (czyli przypisanego mu kontenera) która jest znana dopiero w momencie tworzenia iteratora.

    struct iterator  {
      void*container_data;
      struct iterator_interface *iface;
    }


    pod container data podpinam strukturę w której są dane specyficzna dla rodzaju kontenera
    pod iface podpinam interfejs specyficzny dla rodzaju kontenera

    dzięki temu mogę przekazać do innej metody jedynie iterator, który przejdzie mi przez wszystkie elementy struktury. Nie potrzebuję podawać rodzaju kontenera, odresów itp. wszystko jest w iteratorze, niezależnie od tego jaką strukturę obsługuje.:D:idea:
  • #9 8437285
    Dżyszla
    Poziom 42  
    Posty: 7075
    Pomógł: 1095
    Ocena: 224
    Ależ tak samo zachowują się wskaźniki do określonych struktur. Jeśli jedynym celem ma być defragmentowanie pamięci, bo.. tak, to możesz się zdziwić efektami podejścia, jakie planujesz. W Twoim rozwiązaniu można jedynie wskazać oszczędność 6 (8) bajtów na wskaźnik do innego obszaru pamięci. Poza tym fragmentacja przy obecnych wyposażeniach komputerów w pamięć operacyjną ma marginalne znaczenie (dostęp do losowego adresu pamięci jest prawie tak samo szybki, jak dostęp sekwencyjny), chyba, że przewidujesz, iż będzie intensywnie wykorzystywany plik wymiany.
    Jest za to minus, o którym wspomniałem - rezerwacja dużego bloku pamięci może wymagać znalezienia faktycznie niepodzielnego wolnego miejsca. W ten sposób możesz dostać komunikat braku pamięci nawet, gdy jeszcze będzie wolne miejsce.
  • #10 8439122
    Dr.Vee
    VIP Zasłużony dla elektroda
    Posty: 1784
    Pomógł: 307
    Ocena: 76
    Fakt, na fragmentacji można tutaj trochę zaoszczędzić, ale znacznie więcej na eliminacji narzutu alokacji kilku bloków - mowa o narzucie pamięciowym wprowadzanym przez alokator pamięci dla celów zarządzania blokami.
    Sądzę, że pamięć szybciej się skończy przy alokacji wielu małych bloków. Oczywiście to kwestia skali - mały blok to kilkunaście-kilkadziesiąt bajtów.

    Jeszcze jedna rzecz ze "sztuczek w C" - klist z jądra linuxa: http://isis.poly.edu/kulesh/stuff/src/klist/

    Pozdrawiam,
    Dr.Vee

Podsumowanie tematu

✨ W dyskusji poruszono problem rezerwacji ciągłego obszaru pamięci dla struktur w języku C. Użytkownik chciałby umieścić różne struktury w obrębie jednej struktury, co jest trudne do osiągnięcia z powodu ograniczeń języka C, który nie pozwala na dynamiczne przydzielanie pamięci w obrębie struktury. Uczestnicy sugerowali różne podejścia, takie jak alokacja bloku pamięci z użyciem malloc, co pozwala na umieszczenie struktur jedna po drugiej w pamięci. Zwrócono uwagę na kwestie fragmentacji pamięci oraz na to, że alokacja wielu małych bloków może prowadzić do szybszego wyczerpania dostępnej pamięci. Wskazano również na techniki, takie jak dodawanie tablicy na końcu struktury, co może być użyteczne w niektórych przypadkach.
Wygenerowane przez model językowy.
REKLAMA