Typowe pułapki na 32-bitowy/64-bitowego przenoszenia są:
przyjętym założeniem przez programatora sizeof (void *) == 4 * sizeof (znaki). Jeśli robisz to założenie i np. przydzielaj tablice w ten sposób ("potrzebuję 20 wskaźników, więc przydzielę 80 bajtów"), twój kod zostanie złamany na 64-bitach, ponieważ spowoduje to przepełnienie bufora.
"Kociak-zabójca", int x = (int) i coś; (i odwrotnie, void * ptr = (void *) some_int). Ponownie założenie sizeof (int) == sizeof (void *). Nie powoduje to przepełnienia, ale traci dane - wyższy 32-bitowy wskaźnik, a mianowicie.
Oba te problemy należą do klasy zwanej aliasingiem typu (zakładając tożsamość/wymienność/równoważność na poziomie reprezentacji binarnej między dwoma typami), a takie założenia są wspólne; jak na UN * X, zakładając time_t, size_t, off_t being int, lub na Windows, HANDLE, void * i long being wymienne, itd ...
Założenia dotyczące struktury danych/wykorzystania miejsca stosu (patrz 5. poniżej jako dobrze). W kodzie C/C++ zmienne lokalne są przydzielane na stosie, a używana tam przestrzeń różni się między trybem 32-bitowym a 64-bitowym ze względu na poniższy punkt, a także ze względu na różne reguły przekazywania argumentów (32-bitowy x86 zwykle na stosie, 64-bitowy x86 w części w rejestrach). Kod, który prawie całkowicie ucieka z domyślnym pakietem 32-bitowym, może spowodować awarię przepełnienia stosu na 64-bitach. Jest to stosunkowo łatwe do wykrycia jako przyczyna awarii, ale w zależności od konfiguracji aplikacji trudne do naprawienia.
Różnice w czasie pomiędzy kodem 32-bitowym a 64-bitowym (ze względu na różne rozmiary kodu/ślady posterów w pamięci podręcznej lub różne charakterystyki dostępu do pamięci/różne konwencje wywoływania) mogą przerwać "kalibrację". Powiedz, dla (int i = 0; i < 1000000; ++ i) uśpienia (0); Prawdopodobnie będzie miał różne czasy dla 32bit i 64bit ...
Wreszcie, ABI (interfejs binarny aplikacji). Zwykle istnieją większe różnice między środowiskami 64-bitowymi a 32-bitowymi niż rozmiar wskaźników ... Obecnie istnieją dwie główne "gałęzie" środowisk 64-bitowych, IL32P64 (co używa Win64 - int i long to int32_t, tylko uintptr_t/void * to uint64_t, rozmawiając w kategoriach liczb całkowitych od) i LP64 (jakiego UN * X używa - int to int32_t, long to int64_t, a uintptr_t/void * to uint64_t), ale są też "podziały" różnych reguł wyrównania - niektóre środowiska zakładają długie, zmienne lub podwójne wyrównanie w odpowiednich rozmiarach, podczas gdy inne przyjmują, że są wyrównane w wielokrotnościach czterech bajtów. W 32-bitowym Linuksie wyrównują wszystko do czterech bajtów, podczas gdy w 64-bitowym Linuksie liczba zmiennoprzecinkowa wynosi cztery, długie i podwójne w ośmio-bajtowych wielokrotnościach. Konsekwencją tych reguł jest to, że w wielu przypadkach rozmiar bitu sizeof (struct {...}) i przesunięcie elementów struktury/klasy są różne w środowiskach 32-bitowych i 64-bitowych, nawet jeśli deklaracja typu danych jest całkowicie identyczna. Oprócz wpływu na alokację macierzy/wektorów, problemy te dotyczą również danych w/danych wyjściowych, np. poprzez pliki - jeśli aplikacja 32-bitowa pisze np. struct {char a; int b; char c, long d; podwójny e} do pliku, który została przekompilowana do 64-bitowej aplikacji, wynik nie będzie tym, na co mamy nadzieję. Podane przykłady dotyczą tylko prymitywów języka (char, int, long itp.), Ale oczywiście wpływają na wszelkiego rodzaju typy danych bibliotek zależnych od platformy/środowiska wykonawczego, czy size_t, off_t, time_t, HANDLE, w zasadzie jakiekolwiek nietrywialne struct/union/class ... - więc miejsce na błędy jest tutaj duże,
A ponadto istnieją różnice niższego poziomu, które wchodzą w grę, np. do montażu zoptymalizowanego ręcznie (SSE/SSE2/...); 32-bitowe i 64-bitowe mają różne (liczby) rejestry, różne reguły przekazywania argumentów; to wszystko mocno wpływa na skuteczność takich optymalizacji i jest bardzo prawdopodobne, że np. Kod SSE2 zapewniający najlepszą wydajność w trybie 32-bitowym będzie musiał zostać przepisany/musi zostać ulepszony, aby zapewnić najlepszą wydajność w trybie 64-bitowym.
Istnieją również ograniczenia projektowania kodu, które są bardzo różne w przypadku wersji 32-bitowych i 64-bitowych, w szczególności w zakresie przydzielania/zarządzania pamięcią; aplikacja, która została starannie zakodowana, aby "zmaksymalizować cholerę z memu, który może uzyskać w 32-bitach", będzie miała złożoną logikę, jak/kiedy przydzielić/zwolnić pamięć, wykorzystanie pamięci mapowane, wewnętrzne buforowanie itp. - z których wiele będzie być szkodliwe na 64-bitach, gdzie można "po prostu" skorzystać z ogromnej dostępnej przestrzeni adresowej. Taka aplikacja mogłaby rekompilować się na 64-bitową wersję, ale działa tam gorzej niż jakaś "prastara, prosta, przestarzała wersja", która nie ma optymalizacji pełno-32-bitowych optymalizacji.
Tak więc, w ostatecznym rozrachunku chodzi również o ulepszenia/zyski, a to oznacza więcej pracy, częściowo w programowaniu, częściowo w projektowaniu/wymaganiach. Nawet jeśli twoja aplikacja czysto rekompiluje się zarówno w środowiskach 32-bitowych, jak i 64-bitowych i jest weryfikowana na obu komputerach. , czy faktycznie korzysta z 64-bitów? Czy są jakieś zmiany, które można/należy wprowadzić w logice kodu, aby sprawić, by działał on szybciej/działał szybciej w wersji 64-bitowej? Czy możesz dokonać tych zmian bez łamania kompatybilności wstecznej 32 bitów? Bez negatywnego wpływu na cel 32-bitowy? Gdzie będą ulepszenia i ile możesz zyskać? W przypadku dużego projektu komercyjnego odpowiedzi na te pytania są często ważnymi markami na mapie drogowej, ponieważ punktem wyjścia jest jakiś istniejący "producent pieniądza" ...
awsome anwser :) właśnie tego szukałem :) –
@FredrikBostonWestman to powinieneś to zaakceptować! – gsamaras