Bagikan melalui


Aturan untuk Menggunakan Pointer

Porting kode Anda untuk dikompilasi untuk Microsoft Windows 32 dan 64-bit sangat mudah. Anda hanya perlu mengikuti beberapa aturan sederhana tentang penunjuk transmisi, dan menggunakan jenis data baru dalam kode Anda. Aturan untuk manipulasi pointer adalah sebagai berikut.

  1. Jangan melemparkan pointer ke int, long, ULONG, atau DWORD.

    Jika Anda harus melemparkan pointer untuk menguji beberapa bit, mengatur atau menghapus bit, atau memanipulasi kontennya, gunakan jenis UINT_PTR atau INT_PTR . Jenis ini adalah jenis integral yang menskalakan ke ukuran pointer untuk Windows 32 dan 64-bit (misalnya, ULONG untuk Windows 32-bit dan _int64 untuk Windows 64-bit). Misalnya, asumsikan Anda memindahkan kode berikut:

    ImageBase = (PVOID)((ULONG)ImageBase | 1);

    Sebagai bagian dari proses porting, Anda akan mengubah kode sebagai berikut:

    ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);

    Gunakan UINT_PTR dan INT_PTR jika sesuai (dan jika Anda tidak yakin apakah diperlukan, tidak ada salahnya menggunakannya untuk berjaga-jaga). Jangan melemparkan pointer Anda ke jenis ULONG, LONG, INT, UINT, atau DWORD.

    Perhatikan bahwa HANDLE didefinisikan sebagai void*, jadi mengetik nilai HANDLE ke nilai ULONG untuk menguji, mengatur, atau menghapus 2 bit urutan rendah adalah kesalahan pada Windows 64-bit.

  2. Gunakan fungsi PtrToLong atau PtrToUlong untuk memotong pointer.

    Jika Anda harus memotong pointer ke nilai 32-bit, gunakan fungsi PtrToLong atau PtrToUlong (ditentukan dalam Basetsd.h). Fungsi-fungsi ini menonaktifkan peringatan pemotongan pointer selama durasi panggilan.

    Gunakan fungsi-fungsi ini dengan hati-hati. Setelah Anda mengonversi variabel pointer menggunakan salah satu fungsi ini, jangan pernah menggunakannya sebagai penunjuk lagi. Fungsi-fungsi ini memotong 32 bit atas alamat, yang biasanya diperlukan untuk mengakses memori yang awalnya dirujuk oleh pointer. Menggunakan fungsi-fungsi ini tanpa pertimbangan yang cermat akan menghasilkan kode yang rapuh.

  3. Berhati-hatilah saat menggunakan nilai POINTER_32 dalam kode yang dapat dikompilasi sebagai kode 64-bit. Pengkompilasi akan memperpanjang penunjuk saat ditetapkan ke pointer asli dalam kode 64-bit, bukan memperluas pointer nol.

  4. Berhati-hatilah saat menggunakan nilai POINTER_64 dalam kode yang dapat dikompilasi sebagai kode 32-bit. Pengkompilasi akan memperpanjang penunjuk dalam kode 32-bit, bukan memperluas pointer nol.

  5. Berhati-hatilah menggunakan parameter OUT.

    Misalnya, Anda memiliki fungsi yang didefinisikan sebagai berikut:

    void func( OUT PULONG *PointerToUlong );

    Jangan panggil fungsi ini sebagai berikut.

    ULONG ul;
    PULONG lp;
    func((PULONG *)&ul);
    lp = (PULONG)ul;
    

    Sebagai gantinya, gunakan panggilan berikut.

    PULONG lp;
    func(&lp);
    

    Typecasting &ul ke PULONG* mencegah kesalahan kompilator, tetapi fungsi akan menulis nilai pointer 64-bit ke dalam memori di &ul. Kode ini berfungsi pada Windows 32-bit, tetapi akan menyebabkan kerusakan data pada Windows 64-bit dan akan menjadi kerusakan yang halang dan sulit ditemukan. Intinya: Jangan bermain trik dengan kode C—mudah dan sederhana lebih baik.

  6. Berhati-hatilah dengan antarmuka polimorfik.

    Jangan membuat fungsi yang menerima parameter DWORD untuk data polimorfik. Jika data dapat menjadi penunjuk atau nilai integral, gunakan jenis UINT_PTR atau PVOID .

    Misalnya, jangan membuat fungsi yang menerima array parameter pengecualian yang diketik sebagai nilai DWORD . Array harus berupa array nilai DWORD_PTR . Oleh karena itu, elemen array dapat menyimpan alamat atau nilai integral 32-bit. (Aturan umum adalah bahwa jika jenis aslinya adalah DWORD dan perlu lebar pointer, konversikan ke nilai DWORD_PTR . Itulah sebabnya ada jenis presisi pointer yang sesuai.) Jika Anda memiliki kode yang menggunakan DWORD, ULONG, atau jenis 32-bit lainnya dengan cara polimorfik (yaitu, Anda benar-benar ingin parameter atau anggota struktur memegang alamat), gunakan UINT_PTR menggantikan jenis saat ini.

  7. Gunakan fungsi kelas jendela baru.

    Jika Anda memiliki data privat jendela atau kelas yang berisi pointer, kode Anda harus menggunakan fungsi baru berikut:

    Fungsi-fungsi ini dapat digunakan pada Windows 32 dan 64-bit, tetapi diperlukan pada Windows 64-bit. Bersiaplah untuk transisi dengan menggunakan fungsi-fungsi ini sekarang.

    Selain itu, Anda harus mengakses penunjuk atau menangani data privat kelas menggunakan fungsi baru pada Windows 64-bit. Untuk membantu Anda dalam menemukan kasus-kasus ini, indeks berikut tidak ditentukan dalam Winuser.h selama kompilasi 64-bit:

    • GWL_WNDPROC
    • GWL_HINSTANCE
    • GWL_HWNDPARENT
    • GWL_USERDATA

    Sebagai gantinya, Winuser.h mendefinisikan indeks baru berikut:

    • GWLP_WNDPROC
    • GWLP_HINSTANCE
    • GWLP_HWNDPARENT
    • GWLP_USERDATA
    • GWLP_ID

    Misalnya, kode berikut tidak dikompilasi:

    SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWndProc);

    Ini harus diubah sebagai berikut:

    SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);

    Saat mengatur anggota cbWndExtra dari struktur WNDCLASS , pastikan untuk mencadangkan cukup ruang untuk pointer. Misalnya, jika Anda saat ini memesan byte sizeof(DWORD) untuk nilai pointer, reserve sizeof(DWORD_PTR) byte.

  8. Akses semua data jendela dan kelas menggunakan FIELD_OFFSET.

    Adalah umum untuk mengakses data jendela menggunakan offset yang dikodekan secara permanen. Teknik ini tidak portabel ke Windows 64-bit. Untuk membuat kode Anda portabel, akses jendela dan data kelas Anda menggunakan makro FIELD_OFFSET . Jangan berasumsi bahwa pointer kedua memiliki offset 4.

  9. Jenis LPARAM, WPARAM, dan LRESULT berubah ukuran dengan platform.

    Saat mengkompilasi kode 64-bit, jenis ini diperluas menjadi 64 bit, karena biasanya menyimpan pointer atau jenis integral. Jangan mencampur nilai-nilai ini dengan nilai DWORD, ULONG, UINT, INT, int, atau panjang . Periksa bagaimana Anda menggunakan jenis ini dan pastikan Bahwa Anda tidak secara tidak sengaja memotong nilai.