CRT başlatma
Bu makalede CRT'nin yerel kodda genel durumu nasıl başlatdığı açıklanmaktadır.
Bağlayıcı varsayılan olarak kendi başlangıç kodunu sağlayan CRT kitaplığını içerir. Bu başlangıç kodu CRT kitaplığını başlatır, genel başlatıcıları çağırır ve ardından konsol uygulamaları için kullanıcı tarafından sağlanan main
işlevi çağırır.
Microsoft'a özgü bağlayıcı davranışından yararlanarak kendi genel başlatıcılarınızı belirli bir sırada eklemek önerilmez. Bu kod taşınabilir değildir ve bazı önemli uyarılar ile birlikte gelir.
Genel nesne başlatma
Aşağıdaki C++ kodunu göz önünde bulundurun (C, sabit ifadede işlev çağrısına izin vermediğinden bu koda izin vermez).
int func(void)
{
return 3;
}
int gi = func();
int main()
{
return gi;
}
C/C++ standardına göre yürütülmeden func()
önce main()
çağrılmalıdır. Ama kim diyor?
Çağıranı belirlemenin bir yolu, içinde func()
bir kesme noktası ayarlamak, uygulamada hata ayıklamak ve yığını incelemektir. CRT kaynak kodu Visual Studio'ya eklendiğinden bu mümkündür.
Yığındaki işlevlere göz attığınızda, CRT'nin işlev işaretçileri listesini çağırdığını görürsünüz. Bu işlevler, sınıf örnekleri için öğesine veya oluşturucularına benzer func()
.
CRT, Microsoft C++ derleyicisinden işlev işaretçilerinin listesini alır. Derleyici bir genel başlatıcı gördüğünde, bölüm adı ve XCU
grup adı olan CRT
bölümünde bir dinamik başlatıcı .CRT$XCU
oluşturur. Dinamik başlatıcıların listesini almak için komutunu dumpbin /all main.obj
çalıştırın ve bölümünde arama yapın .CRT$XCU
. Komut yalnızca C dosyası olarak değil C++ dosyası olarak derlendiğinde main.cpp
uygulanır. Bu örneğe benzer olmalıdır:
SECTION HEADER #6
.CRT$XCU name
0 physical address
0 virtual address
4 size of raw data
1F2 file pointer to raw data (000001F2 to 000001F5)
1F6 file pointer to relocation table
0 file pointer to line numbers
1 number of relocations
0 number of line numbers
40300040 flags
Initialized Data
4 byte align
Read Only
RAW DATA #6
00000000: 00 00 00 00 ....
RELOCATIONS #6
Symbol Symbol
Offset Type Applied To Index Name
-------- ---------------- ----------------- -------- -------
00000000 DIR32 00000000 C ??__Egi@@YAXXZ (void __cdecl `dynamic initializer for 'gi''(void))
CRT iki işaretçi tanımlar:
.CRT$XCA
içinde__xc_a
.CRT$XCZ
içinde__xc_z
Hiçbir grupta ve __xc_z
dışında __xc_a
tanımlanmış başka simge yok.
Bağlayıcı çeşitli .CRT
alt bölümleri okuduğunda (bölümünden $
sonraki bölüm), bunları bir bölümde birleştirir ve alfabetik olarak sıralar. Bu, kullanıcı tanımlı genel başlatıcıların (Microsoft C++ derleyicisinin yerleştirdiği .CRT$XCU
) her zaman sonra .CRT$XCA
ve öncesinde .CRT$XCZ
geldiği anlamına gelir.
Bölüm şu örneğe benzemelidir:
.CRT$XCA
__xc_a
.CRT$XCU
Pointer to Global Initializer 1
Pointer to Global Initializer 2
.CRT$XCZ
__xc_z
CRT kitaplığı, görüntü yüklendikten sonra belleğe yerleştirildikleri yöntem nedeniyle genel başlatıcılar listesinin başlangıç ve bitişini belirlemek için hem hem de __xc_a
__xc_z
kullanır.
Başlatma için bağlayıcı özellikleri
C++ Standardı, kullanıcı tarafından sağlanan genel başlatıcı için çeviri birimleri arasında göreli sıra belirtmek için uygun bir yol sağlamaz. Ancak, Microsoft bağlayıcısı alt bölümler alfabetik olarak sipariş ettiğinden .CRT
, başlatma sırasını belirtmek için bu sıralamadan yararlanmak mümkündür. Bu Microsoft'a özgü tekniği önermiyoruz ve gelecekteki bir sürümde bozulabilir. Bu belgeyi yalnızca tanılaması zor yollarla bozuk kod oluşturmanızı engelleyebilecek şekilde belgeledik.
Visual Studio 2019 sürüm 16.11'den başlayarak kodunuzdaki sorunları önlemeye yardımcı olmak için varsayılan olarak iki yeni uyarı ekledik: C5247 ve C5248. Kendi başlatıcılarınızı oluştururken sorunları algılamak için bu uyarıları etkinleştirin.
Derleyici tarafından oluşturulan dinamik başlatıcılara belirli bir göreli sırada oluşturmak için kullanılmayan ayrılmış bölüm adlarına başlatıcılar ekleyebilirsiniz:
#pragma section(".CRT$XCT", read)
// 'i1' is guaranteed to be called before any compiler generated C++ dynamic initializer
__declspec(allocate(".CRT$XCT")) type i1 = f;
#pragma section(".CRT$XCV", read)
// 'i2' is guaranteed to be called after any compiler generated C++ dynamic initializer
__declspec(allocate(".CRT$XCV")) type i2 = f;
ve adları .CRT$XCT
.CRT$XCV
şu anda derleyici veya CRT kitaplığı tarafından kullanılmaz, ancak gelecekte kullanılmayabileceklerinin garantisi yoktur. Ayrıca değişkenleriniz derleyici tarafından iyileştirilebiliyor. Bu tekniği benimsemeden önce olası mühendislik, bakım ve taşınabilirlik sorunlarını göz önünde bulundurun.
Ayrıca bkz.
_initterm, _initterm_e
C çalışma zamanı (CRT) ve C++ Standart Kitaplığı (STL) .lib
dosyaları