Właśnie skończyłem test w ramach rozmowy kwalifikacyjnej i jedno pytanie mnie zaskoczyło, nawet używając Google w celach informacyjnych. Chciałbym zobaczyć, co załoga StackOverflow może z tym zrobić:
Ta
memset_16aligned
funkcja wymaga przekazania 16-bajtowego wyrównanego wskaźnika, w przeciwnym razie nastąpi awaria.a) W jaki sposób przydzielisz 1024 bajty pamięci i dopasujesz ją do granicy 16 bajtów?
b) Zwolnij pamięć pomemset_16aligned
wykonaniu.
{
void *mem;
void *ptr;
// answer a) here
memset_16aligned(ptr, 0, 1024);
// answer b) here
}
c
memory-management
JimDaniel
źródło
źródło
Odpowiedzi:
Oryginalna odpowiedź
Naprawiono odpowiedź
Wyjaśnienie zgodnie z prośbą
Pierwszym krokiem jest przydzielenie wystarczającej ilości wolnego miejsca, na wszelki wypadek. Ponieważ pamięć musi być wyrównana do 16 bajtów (co oznacza, że początkowy adres bajtu musi być wielokrotnością 16), dodanie 16 dodatkowych bajtów gwarantuje, że mamy wystarczająco dużo miejsca. Gdzieś w pierwszych 16 bajtach znajduje się 16-bajtowy wyrównany wskaźnik. (Należy pamiętać, że
malloc()
ma powrócić wskaźnik, który jest dostatecznie dobrze wyrównany dla dowolnego . Celów, jednak sens „każdy” jest przede wszystkim na takie rzeczy jak podstawowe typy -long
,double
,long double
,long long
., A wskaźniki do obiektów i wskaźniki do funkcji Kiedy jesteś robiąc bardziej wyspecjalizowane rzeczy, np. grając z systemami graficznymi, mogą wymagać bardziej rygorystycznego dostosowania niż reszta systemu - stąd takie pytania i odpowiedzi).Następnym krokiem jest konwersja wskaźnika pustki na wskaźnik char; Niezależnie od GCC, nie powinieneś wykonywać arytmetyki wskaźnika na pustych wskaźnikach (a GCC ma opcje ostrzegania, aby poinformować cię, gdy nadużyjesz). Następnie dodaj 16 do wskaźnika początkowego. Załóżmy, że
malloc()
zwrócił ci niemożliwie źle ustawiony wskaźnik: 0x800001. Dodanie 16 daje 0x800011. Teraz chcę zaokrąglić w dół do granicy 16 bajtów - więc chcę zresetować ostatnie 4 bity na 0. 0x0F ma ostatnie 4 bity ustawione na jeden; dlatego~0x0F
ma wszystkie bity ustawione na jeden oprócz ostatnich czterech. Po dodaniu 0x800011 otrzymujemy 0x800010. Możesz iterować po innych odsunięciach i zobaczyć, że działa ta sama arytmetyka.Ostatnim krokiem
free()
jest proste: zawsze i tylko, powrót dofree()
wartości, która z jednejmalloc()
,calloc()
lubrealloc()
zwrócone do siebie - nic innego nie jest katastrofą. Podałeś poprawnie,mem
aby zachować tę wartość - dziękuję. Bezpłatny wydaje to.Wreszcie, jeśli wiesz o wewnętrznych
malloc
elementach pakietu systemu , możesz zgadywać, że może on zwrócić 16-bajtowe dane (lub może być 8-bajtowe). Jeśli byłby wyrównany do 16 bajtów, nie musiałbyś mrugać z wartościami. Jest to jednak podejrzane i nieprzenośne - innemalloc
pakiety mają różne minimalne wyrównania, a zatem zakładanie jednej rzeczy, gdy robi coś innego, prowadziłoby do zrzutów rdzenia. W szerokich granicach to rozwiązanie jest przenośne.Ktoś inny wymieniony
posix_memalign()
jako inny sposób na uzyskanie wyrównanej pamięci; nie jest to dostępne wszędzie, ale często można je wdrożyć, wykorzystując to jako podstawę. Zauważ, że wygodnie było, aby wyrównanie miało moc 2; inne dopasowania są bardziej chaotyczne.Jeszcze jeden komentarz - ten kod nie sprawdza, czy alokacja się powiodła.
Poprawka
Programista Windows zauważył, że nie można wykonywać operacji maskowania bitów na wskaźnikach, i rzeczywiście GCC (testowane 3.4.6 i 4.3.1) tak narzeka. Tak więc następuje poprawiona wersja kodu podstawowego - przekonwertowana na program główny. Jak już wspomniano, mogłem również dodać tylko 15 zamiast 16. Używam,
uintptr_t
odkąd C99 jest wystarczająco długi, aby był dostępny na większości platform. Gdyby nie do użyciaPRIXPTR
wprintf()
instrukcjach, wystarczyłoby użyć#include <stdint.h>
zamiast#include <inttypes.h>
. [Ten kod zawiera poprawkę wskazaną przez CR , która przypominała punkt, który Bill K po raz pierwszy przedstawił kilka lat temu, a który udało mi się przeoczyć do tej pory.]A oto wersja nieco bardziej uogólniona, która będzie działać dla rozmiarów o sile 2:
Aby przekształcić
test_mask()
w funkcję alokacji ogólnego przeznaczenia, pojedyncza wartość zwrotna z alokatora musiałaby zakodować adres wydania, jak wskazało kilka osób w swoich odpowiedziach.Problemy z ankieterami
Uri skomentował: Może mam dziś rano problem ze zrozumieniem czytania, ale jeśli pytanie z wywiadu wyraźnie mówi: „Jak byś przydzielił 1024 bajty pamięci” i wyraźnie przydzielisz więcej. Czy nie byłaby to automatyczna porażka ankietera?
Moja odpowiedź nie pasuje do komentarza złożonego z 300 znaków ...
To chyba zależy. Myślę, że większość ludzi (w tym ja) przyjęła pytanie w znaczeniu „Jak byś przydzielił przestrzeń, w której można przechowywać 1024 bajty danych, a adres podstawowy to wielokrotność 16 bajtów”. Jeśli ankieter naprawdę miał na myśli, jak można przydzielić 1024 bajty (tylko) i ustawić 16 bajtów na wyrównanie, wówczas opcje są bardziej ograniczone.
Jeśli jednak ankieter oczekiwałby jednej z tych odpowiedzi, spodziewałbym się, że rozpozna, że to rozwiązanie odpowiada na ściśle powiązane pytanie, a następnie ponownie sformułuje swoje pytanie, aby skierować rozmowę we właściwym kierunku. (Ponadto, jeśli ankieter stałby się naprawdę niespokojny, to nie chciałbym pracy; jeśli odpowiedź na niewystarczająco precyzyjne wymaganie zostanie zestrzelona w płomieniach bez korekty, to ankieter nie jest kimś, dla kogo można bezpiecznie pracować).
Świat się rozwija
Tytuł pytania zmienił się ostatnio. Było Rozwiązać wyrównanie pamięci w C pytanie wywiad, które stumped mnie . Zmieniony tytuł ( Jak przydzielić wyrównaną pamięć tylko przy użyciu biblioteki standardowej? ) Wymaga nieco zmienionej odpowiedzi - ten dodatek ją zawiera.
Dodano funkcję C11 (ISO / IEC 9899: 2011)
aligned_alloc()
:POSIX definiuje
posix_memalign()
:Można użyć jednego lub obu z nich, aby odpowiedzieć na pytanie teraz, ale tylko funkcja POSIX była opcją, gdy pierwotnie udzielono odpowiedzi na pytanie.
Za kulisami nowa funkcja pamięci wyrównanej wykonuje dokładnie to samo zadanie, co przedstawione w pytaniu, z tym wyjątkiem, że ma możliwość łatwiejszego wymuszenia wyrównania i śledzenia wewnętrznego początku wyrównanej pamięci, aby kod nie mam do czynienia szczególnie - zwalnia pamięć zwróconą przez użytą funkcję alokacji.
źródło
<inttypes.h>
dostępny z C99 (przynajmniej dla ciągu formatu - prawdopodobnie wartości należy przekazać za pomocą rzutowania :)(uintptr_t)mem, (uintptr_t)ptr
. Łańcuch formatu zależy od konkatenacji łańcucha, a makro PRIXPTR jest poprawnym specyfikatoremprintf()
długości i typu dla danych szesnastkowych dlauintptr_t
wartości. Alternatywą jest użycie,%p
ale wynik jest różny w zależności od platformy (niektóre dodają wiodące0x
, większość nie) i zwykle jest zapisywany małymi cyframi szesnastkowymi, co mi się nie podoba; to, co napisałem, jest jednolite na różnych platformach.Trzy nieco różne odpowiedzi w zależności od tego, jak spojrzysz na pytanie:
1) Odpowiednim rozwiązaniem dla dokładnie zadanego pytania jest rozwiązanie Jonathana Lefflera, z tym wyjątkiem, że aby zaokrąglić w górę do wyrównania do 16, potrzebujesz tylko 15 dodatkowych bajtów, a nie 16.
ZA:
B:
2) Aby uzyskać bardziej ogólną funkcję alokacji pamięci, osoba dzwoniąca nie musi śledzić dwóch wskaźników (jednego do użycia, a drugiego do zwolnienia). Więc przechowujesz wskaźnik do „prawdziwego” bufora poniżej bufora wyrównanego.
ZA:
B:
Zauważ, że w przeciwieństwie do (1), w którym do mema dodano tylko 15 bajtów, ten kod może faktycznie zmniejszyć wyrównanie, jeśli twoja implementacja zagwarantuje wyrównanie 32 bajtów z malloc (mało prawdopodobne, ale teoretycznie implementacja C może mieć 32 bajty wyrównany typ). To nie ma znaczenia, jeśli wszystko, co robisz, to zadzwoń do memset_16aligned, ale jeśli użyjesz pamięci dla struktury, może to mieć znaczenie.
Nie jestem pewien, co jest dobrym rozwiązaniem w tym zakresie (poza ostrzeżeniem użytkownika, że zwrócony bufor niekoniecznie jest odpowiedni dla dowolnych struktur), ponieważ nie ma możliwości programowego określenia, co to jest gwarancja wyrównania specyficzna dla implementacji. Wydaje mi się, że przy starcie możesz przydzielić dwa lub więcej 1-bajtowych buforów i zakładam, że najgorszym wyrównaniem, jakie widzisz, jest wyrównanie gwarantowane. Jeśli się mylisz, marnujesz pamięć. Każdy, kto ma lepszy pomysł, powiedz tak ...
[ Dodano : „Standardowa” sztuczka polega na utworzeniu związku „prawdopodobnie będą to maksymalnie wyrównane typy” w celu ustalenia wymaganego wyrównania. Maksymalnie wyrównane typy to (w C99) „
long long
”, „long double
”, „void *
” lub „void (*)(void)
”; jeśli to<stdint.h>
zrobisz, prawdopodobnie możesz użyć „intmax_t
” zamiastlong long
(a na maszynach Power 6 (AIX)intmax_t
dałbyś 128-bitową liczbę całkowitą). Wymagania dotyczące wyrównania dla tego związku można określić, osadzając go w strukturze za pomocą pojedynczego znaku, po którym następuje związek:Następnie użyłbyś większego z żądanego wyrównania (w przykładzie 16) i
align
wartości obliczonej powyżej.W (64-bitowym) systemie Solaris 10 wydaje się, że podstawowym wyrównaniem wyniku
malloc()
jest wielokrotność 32 bajtów.]
W praktyce wyrównani alokatorzy często przyjmują parametr wyrównania, a nie jest on podłączony na stałe. Więc użytkownik przekaże rozmiar struktury, na której mu zależy (lub najmniejszą moc 2 większą lub równą temu) i wszystko będzie dobrze.
3) Użyj tego, co zapewnia platforma:
posix_memalign
dla POSIX,_aligned_malloc
w systemie Windows.4) Jeśli używasz C11, najczystszą - przenośną i zwięzłą - opcją jest użycie standardowej funkcji biblioteki,
aligned_alloc
która została wprowadzona w tej wersji specyfikacji języka.źródło
ASSERT(mem);
do sprawdzania wyników alokacji;assert
służy do wychwytywania błędów programowania i nie braku zasobów w czasie wykonywania.char *
i asize_t
spowoduje błąd. Musisz użyć czegoś takiegouintptr_t
.Możesz także spróbować
posix_memalign()
(oczywiście na platformach POSIX).źródło
Oto alternatywne podejście do części „zaokrąglania w górę”. Nie jest to najlepiej kodowane rozwiązanie, ale wykonuje zadanie, a ten typ składni jest nieco łatwiejszy do zapamiętania (plus działałby dla wartości wyrównania, które nie są potęgą 2).
uintptr_t
Obsada była konieczna, aby uspokoić kompilator; arytmetyka wskaźników nie przepada za dzieleniem ani mnożeniem.źródło
Niestety w C99 wydaje się dość trudne zagwarantowanie dowolnego wyrównania w sposób, który byłby przenośny w dowolnej implementacji C zgodnej z C99. Dlaczego? Ponieważ nie można zagwarantować, że wskaźnik będzie „adresem bajtu”, można sobie wyobrazić, używając płaskiego modelu pamięci. Nie jest też zagwarantowana reprezentacja uintptr_t , który sam jest opcjonalnym typem.
Być może znamy niektóre implementacje, które używają reprezentacji dla void * (i z definicji także char * ), który jest prostym adresem bajtowym, ale do C99 jest nieprzejrzysty dla nas, programistów. Implementacja może reprezentować wskaźnik przez zestaw { segment , offset }, gdzie offset może mieć wyrównanie „kto wie, co” „w rzeczywistości”. Wskaźnik może być nawet jakąś formą wartości wyszukiwania w tablicy skrótów, a nawet wartością odnośnika z listą połączoną. Może kodować informacje o granicach.
W ostatnim szkicu C1X dla standardu C widzimy słowo kluczowe _Alignas . To może trochę pomóc.
Jedyną gwarancją, jaką daje nam C99, jest to, że funkcje alokacji pamięci zwrócą wskaźnik odpowiedni do przypisania do wskaźnika wskazującego na dowolny typ obiektu. Ponieważ nie możemy określić wyrównania obiektów, nie możemy wdrożyć własnych funkcji alokacji odpowiedzialnych za wyrównanie w dobrze zdefiniowany, przenośny sposób.
Dobrze byłoby pomylić się z tym twierdzeniem.
źródło
aligned_alloc()
. (C ++ 11/14 / 1z wciąż go nie ma)._Alignas()
i C ++alignas()
nie robią nic dla dynamicznej alokacji, tylko dla automatycznego i statycznego przechowywania (lub struktury).Na froncie wypełniającym 16 vs 15 bajtów rzeczywista liczba, którą musisz dodać, aby uzyskać wyrównanie N, wynosi max (0, NM), gdzie M jest naturalnym wyrównaniem alokatora pamięci (i oba są potęgami 2).
Ponieważ minimalne wyrównanie pamięci dowolnego alokatora wynosi 1 bajt, 15 = maks. (0,16-1) jest konserwatywną odpowiedzią. Jeśli jednak wiesz, że twój alokator pamięci da ci 32-bitowe wyrównane adresy int (co jest dość powszechne), mógłbyś użyć 12 jako podkładki.
Nie jest to ważne w tym przykładzie, ale może być ważne w systemie wbudowanym z 12 KB pamięci RAM, gdzie liczy się każdy zapisany int.
Najlepszym sposobem na jego zaimplementowanie, jeśli naprawdę chcesz zapisać każdy możliwy bajt, jest makra, dzięki czemu możesz zasilić go rodzimym wyrównaniem pamięci. Ponownie jest to prawdopodobnie przydatne tylko w systemach wbudowanych, w których trzeba zapisać każdy bajt.
W poniższym przykładzie w większości systemów wartość 1 jest odpowiednia dla
MEMORY_ALLOCATOR_NATIVE_ALIGNMENT
, jednak w przypadku naszego teoretycznego systemu osadzonego z 32-bitowymi wyrównanymi alokacjami, poniższe mogą zaoszczędzić trochę cennej pamięci:źródło
Być może byliby zadowoleni ze znajomości memalign ? Jonathan Leffler podkreśla, że istnieją dwie nowsze preferowane funkcje, o których warto wiedzieć.
Ups, Florin mnie pobił. Jeśli jednak przeczytasz stronę podręcznika, do której linkowałem, najprawdopodobniej zrozumiesz przykład dostarczony przez wcześniejszy plakat.
źródło
memalign
funkcja jest przestarzała ialigned_alloc
czyposix_memalign
powinien być stosowany zamiast”. Nie wiem, co powiedział w październiku 2008 r. - ale prawdopodobnie nie wspomniałaligned_alloc()
o tym, ponieważ dodano go do C11.Robimy to cały czas dla Accelerate.framework, mocno wektorowej biblioteki OS X / iOS, w której musimy cały czas zwracać uwagę na wyrównanie. Jest całkiem sporo opcji, z których jednej lub dwóch nie widziałem wspomnianych powyżej.
Najszybszą metodą dla takiej małej tablicy jest po prostu przyklejenie jej na stos. Z GCC / clang:
Nie wymaga darmowego (). Zazwyczaj są to dwie instrukcje: odejmij 1024 od wskaźnika stosu, a następnie ORAZ wskaźnik stosu za pomocą opcji -alignment. Prawdopodobnie requester potrzebował danych na stercie, ponieważ jego żywotność tablicy przekroczyła stos lub rekurencja jest w pracy lub przestrzeń stosu ma poważną wagę.
W OS X / iOS wszystkie połączenia do malloc / calloc / etc. są zawsze wyrównane 16 bajtów. Jeśli potrzebujesz na przykład wyrównania 32 bajtów dla AVX, możesz użyć posix_memalign:
Niektórzy wspominali o interfejsie C ++, który działa podobnie.
Nie należy zapominać, że strony są wyrównane do dużych potęg dwóch, więc bufory wyrównane do strony są również wyrównane do 16 bajtów. Zatem mmap () i valloc () oraz inne podobne interfejsy są również opcjami. Zaletą mmap () jest to, że bufor można przydzielić wstępnie zainicjowany z czymś niezerowym, jeśli chcesz. Ponieważ mają one wyrównany rozmiar strony, nie uzyskasz minimalnego przydziału z nich, i prawdopodobnie będzie podlegać usterce maszyny wirtualnej przy pierwszym dotknięciu.
Tandetny: Włącz malloc strażnika lub podobny. Bufory o rozmiarze n * 16 bajtów, takie jak ten, będą wyrównane n * 16 bajtów, ponieważ maszyna wirtualna jest używana do przechwytywania przekroczeń, a jej granice znajdują się na granicach strony.
Niektóre funkcje Accelerate.framework przyjmują dostarczony przez użytkownika bufor tymczasowy do wykorzystania jako przestrzeń do rysowania. Tutaj musimy założyć, że przekazany nam bufor jest bardzo źle ustawiony, a użytkownik aktywnie próbuje utrudnić nam życie. (Nasze przypadki testowe przyklejają stronę ochronną tuż przed i za buforem temp, aby podkreślić złośliwość.) Tutaj zwracamy minimalny rozmiar, którego potrzebujemy, aby zagwarantować gdzieś w nim 16-bajtowy segment, a następnie ręcznie wyrównać bufor. Ten rozmiar jest pożądany_wymiar + wyrównanie - 1. Tak więc w tym przypadku jest to 1024 + 16-1 = 1039 bajtów. Następnie wyrównaj tak:
Dodanie wyrównania-1 spowoduje przesunięcie wskaźnika poza pierwszy wyrównany adres, a następnie ORAZ za pomocą -alignment (np. 0xfff ... ff0 dla wyrównania = 16) sprowadzi go z powrotem do wyrównanego adresu.
Jak opisano w innych postach, w innych systemach operacyjnych bez 16-bajtowych gwarancji wyrównania, możesz wywołać malloc o większym rozmiarze, odłożyć wskaźnik za darmo () później, a następnie wyrównać, jak opisano bezpośrednio powyżej i użyć wyrównanego wskaźnika, podobnie jak opisane dla naszego przypadku bufora temp.
Jeśli chodzi o wyrównany_memset, jest to raczej głupie. Musisz tylko zapętlić do 15 bajtów, aby osiągnąć wyrównany adres, a następnie przejść do wyrównanych sklepów, a następnie na końcu jakiś możliwy kod czyszczenia. Możesz nawet wykonać bity czyszczące w kodzie wektorowym, albo jako niepasowane sklepy, które pokrywają się z wyrównanym regionem (pod warunkiem, że długość wynosi co najmniej długość wektora), lub używając czegoś takiego jak movmaskdqu. Ktoś jest po prostu leniwy. Prawdopodobnie rozsądnym pytaniem jest, czy osoba przeprowadzająca wywiad chce wiedzieć, czy czujesz się komfortowo ze standardem stdint.h, operatorami bitowymi i podstawami pamięci, więc wymyślony przykład można wybaczyć.
źródło
Dziwię noone przegłosowanych się Shao „s odpowiedź że, jak rozumiem, jest to niemożliwe do zrobienia, co poprosił w standardzie C99, ponieważ konwersja wskaźnik do integralnego formalnie typu zachowanie jest niezdefiniowane. (Oprócz standardu pozwalającego na konwersję
uintptr_t
<->void*
, ale standard nie wydaje się pozwalać na jakiekolwiek manipulowanieuintptr_t
wartością, a następnie konwertowanie jej z powrotem.)źródło
unsigned char* myptr
; a następnie obliczymy `mptr + = (16- (uintptr_t) my_ptr) i 0x0F, zachowanie będzie zdefiniowane na wszystkich implementacjach, które definiują my_ptr, ale to, czy wynikowy wskaźnik zostanie wyrównany, będzie zależeć od odwzorowania między bitami i adresami uintptr_t.użycie memalign, Aligned-Memory-Blocks może być dobrym rozwiązaniem problemu.
źródło
memalign
funkcja jest przestarzała ialigned_alloc
czyposix_memalign
powinien być stosowany zamiast”. Nie wiem, co powiedział w październiku 2010 r.Pierwszą rzeczą, która przyszła mi do głowy podczas czytania tego pytania, było zdefiniowanie wyrównanej struktury, utworzenie jej, a następnie wskazanie.
Czy brakuje mi podstawowego powodu, skoro nikt inny tego nie sugerował?
Jako sidenote, ponieważ użyłem tablicy char (zakładając, że char systemu to 8 bitów (tj. 1 bajt)), nie widzę potrzeby użycia
__attribute__((packed))
koniecznej (popraw mnie, jeśli się mylę), ale to ułożyłem w każdym razie.Działa to na dwóch systemach, na których wypróbowałem, ale możliwe jest, że istnieje optymalizacja kompilatora, której nie jestem świadomy, dając mi fałszywie pozytywne wyniki w zakresie skuteczności kodu. Użyłem
gcc 4.9.2
na OSX igcc 5.2.1
Ubuntu.źródło
Specyficzne dla MacOS X:
Obsługiwane jest C11, więc możesz po prostu wywołać wyrównany_malloc (16, rozmiar).
MacOS X wybiera kod, który jest zoptymalizowany dla poszczególnych procesorów w czasie uruchamiania, dla memset, memcpy i memmove, a ten kod wykorzystuje sztuczki, o których nigdy nie słyszałeś, aby przyspieszyć. 99% szans, że zestaw działa szybciej niż jakikolwiek zestaw odręczny16, co sprawia, że całe pytanie jest bezcelowe.
Jeśli chcesz w 100% przenośne rozwiązanie, przed C11 nie ma takiego rozwiązania. Ponieważ nie ma przenośnego sposobu testowania wyrównania wskaźnika. Jeśli nie musi być w 100% przenośny, możesz użyć
Zakłada się, że wyrównanie wskaźnika jest przechowywane w najniższych bitach podczas konwertowania wskaźnika na int bez znaku. Konwersja na unsigned int traci informacje i jest zdefiniowana implementacja, ale to nie ma znaczenia, ponieważ nie przekształcamy wyniku z powrotem na wskaźnik.
Straszne jest oczywiście to, że oryginalny wskaźnik należy zapisać gdzieś, aby wywołać z nim free (). Podsumowując, naprawdę wątpiłbym w mądrość tego projektu.
źródło
aligned_malloc
w OS X? Używam Xcode 6.1 i nie jest on nigdzie zdefiniowany w iOS SDK, ani nie jest zadeklarowany w żadnym miejscu/usr/include/*
.aligned_alloc()
, ale też nie została zadeklarowana. Z GCC 5.3.0 otrzymuję ciekawe wiadomościalig.c:7:15: error: incompatible implicit declaration of built-in function ‘aligned_alloc’ [-Werror]
ialig.c:7:15: note: include ‘<stdlib.h>’ or provide a declaration of ‘aligned_alloc’
. Kod rzeczywiście zawierał<stdlib.h>
, ale ani-std=c11
nie-std=gnu11
zmieniał komunikatów o błędach.Możesz także dodać 16 bajtów, a następnie przesunąć oryginalny plik ptr do 16-bitowego wyrównany, dodając (16-mod) jak poniżej wskaźnika:
źródło
Jeśli istnieją ograniczenia, których nie można zmarnować ani jednym bajtem, to rozwiązanie działa: Uwaga: Istnieje przypadek, w którym można to wykonać w nieskończoność: D
źródło
%
operator jest zdefiniowanyvoid*
w sensowny sposób?Do rozwiązania wykorzystałem koncepcję wypełniania, która wyrównuje pamięć i nie marnuje pamięci pojedynczego bajtu.
Jeśli istnieją takie ograniczenia, nie można zmarnować ani jednego bajtu. Wszystkie wskaźniki przypisane do malloc są wyrównane 16 bajtów.
Obsługiwane jest C11, więc możesz po prostu zadzwonić
aligned_alloc (16, size)
.źródło
malloc()
jest rzeczywiście wyrównany do 16-bajtowej granicy, ale nic w żadnym standardowym standardzie nie gwarantuje - będzie po prostu wystarczająco dobrze wyrównany do dowolnego zastosowania, a w wielu systemach 32-bitowych wyrównanie na 8-bajtowa granica jest wystarczająca, a dla niektórych wystarczająca jest 4-bajtowa granica.Mam nadzieję, że to najprostsza implementacja, daj mi znać swoje komentarze.
źródło
źródło
add += 16 - (add % 16)
.(2 - (2 % 16)) == 0
.