Aracılığıyla paylaş


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_zdışı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$XCZgeldiğ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ı