Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Dalam artikel ini, Anda mempelajari tentang panduan untuk menerapkan fungsi intrinsik kustom dalam visualisasi NatVis. Untuk informasi selengkapnya tentang NatVis, lihat Membuat tampilan kustom objek C++.
Sintaksis
File NatVis dapat menentukan fungsi intrinsik menggunakan sintaks berikut:
<Intrinsic Name="Func" Expression="arg + 1">
<Parameter Name="arg" Type="int" />
</Intrinsic>
Setelah definisi ada, ekspresi debugger apa pun dapat memanggil fungsi, seperti fungsi lainnya. Misalnya, menggunakan definisi NatVis sebelumnya, ekspresi Func(3) dievaluasi ke 4.
Elemen <Intrinsic> dapat muncul baik di tingkat file, atau di dalam elemen <Type>, sebelum elemen lain. Fungsi intrinsik yang ditentukan dalam <Type> menentukan fungsi anggota dari jenis tersebut, sementara fungsi intrinsik yang ditentukan di luar <Type> menentukan fungsi global. Misalnya:
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="std::vector<*>">
<Intrinsic Name="size" Expression="_Mypair._Myval2._Mylast - _Mypair._Myval2._Myfirst" />
<Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myend - _Mypair._Myval2._Myfirst" />
</Type>
<Intrinsic Name="LOWORD" Expression="arg & 0xFFFF">
<Parameter Name="arg" Type="unsigned int" />
</Intrinsic>
</AutoVisualizer>
Dalam contoh sebelumnya, size() dan capacity() didefinisikan sebagai fungsi member dari kelas std::vector, jadi setiap kali ekspresi mengevaluasi vector.size(), ekspresi tersebut benar-benar akan mengevaluasi vector._Mypair._Myval2._Mylast - vector._Mypair._Myval2._Myfirst, alih-alih melakukan evaluasi fungsi.
Demikian pula, LOWORD(0x12345678) mengembalikan 0x5678, juga tanpa func-eval.
Untuk contoh lain, lihat ekspansi intrinsik.
Panduan untuk menggunakan fungsi intrinsik
Perhatikan panduan berikut saat menggunakan fungsi intrinsik:
Fungsi intrinsik dapat kelebihan beban, baik dengan fungsi yang ditentukan PDB, atau satu sama lain.
Ketika fungsi intrinsik bertentangan dengan fungsi yang ditentukan PDB dengan nama dan daftar argumen yang sama, fungsi intrinsik akan menang. Anda tidak dapat melakukan evaluasi fungsi PDB jika ada fungsi intrinsik yang setara.
Anda tidak dapat mengambil alamat dari fungsi intrinsik; Anda hanya dapat memanggilnya.
Fungsi anggota intrinsik harus termasuk dalam tampilan default dari tipe yang bersangkutan agar dapat dievaluasi dalam ekspresi. Misalnya, entri jenis dengan batasan
IncludeViewmungkin tidak menentukan fungsi intrinsik.Fungsi intrinsik dapat dipanggil dari ekspresi apa pun, termasuk ekspresi NatVis. Fungsi intrinsik juga dapat saling memanggil. Namun, fungsi intrinsik yang menggunakan rekursi saat ini tidak didukung. Misalnya:
<!-- OK --> <Intrinsic Name="Func2" Expression="this->Func3(arg + 1)"> <Parameter Name="arg" Type="int" /> </Intrinsic> <Intrinsic Name="Func3" Expression="arg + 1"> <Parameter Name="arg" Type="int"/> </Intrinsic> <!-- Unsupported --> <Intrinsic Name="Func2" Expression="this->Func3(arg + 1)"> <Parameter Name="arg" Type="int" /> </Intrinsic> <Intrinsic Name="Func3" Expression="Func2(arg + 1)"> <Parameter Name="arg" Type="int"/> </Intrinsic> <!-- Also unsupported--> <Intrinsic Name="Fib" Expression="(n <= 1) ? 1 : Fib(n - 1) + Fib(n - 2)"> <Parameter Name="n" Type="int"/> </Intrinsic>Secara default, fungsi intrinsik diasumsikan bebas efek samping. Artinya, mereka dapat dipanggil dalam konteks yang melarang efek samping, dan ekspresi implementasi tidak diizinkan untuk berisi efek samping.
Definisi dapat mengambil alih perilaku ini dengan menentukan atribut
SideEffectdalam deklarasi. Jika fungsi ditandai sebagai memiliki efek samping, efek samping dalam ekspresi implementasi menjadi diizinkan. Namun, memanggil fungsi dalam konteks di mana efek samping dilarang tidak lagi diizinkan.Ketika definisi dua fungsi intrinsik bertentangan satu sama lain (nama yang sama, tanda tangan yang sama), yang terakhir menang (dalam file yang sama).
Dalam file yang berbeda, instans dalam file dengan prioritas yang lebih tinggi menang (proyek lebih tinggi dari direktori pengguna, yang lebih tinggi dari direktori penginstalan). Jika definisi berprioritas lebih tinggi berisi ekspresi yang tidak mengurai, definisi tersebut diabaikan, dan definisi prioritas tertinggi berikutnya digunakan sebagai gantinya.
Panduan untuk menerapkan fungsi Intrinsik
Fungsi intrinsik mendukung dua kemungkinan bentuk implementasi:
Berbasis ekspresi
File NatVis mendefinisikan ekspresi yang mengevaluasi ke nilai pengembalian dari fungsi. Ekspresi dapat menggunakan argumen apa pun yang diteruskan ke dalamnya yang dinyatakan sebagai elemen
<Parameter>. Fungsi yang didefinisikan dalam kelas juga diasumsikan sebagai fungsi "instance", dan juga dapat mengakses "pointer this".Berbasis ekstensi
File NatVis menyediakan instruksi untuk memanggil ekstensi debugger untuk benar-benar mengevaluasi fungsi. Ekstensi debugger memiliki akses penuh ke API Concord, dan memiliki kemampuan untuk melakukan tugas yang tidak dimungkinkan dalam ekspresi NatVis.
Untuk menyediakan implementasi berbasis ekstensi, elemen <Intrinsic> harus menghilangkan atribut Expression dan, sebagai gantinya, menyediakan atribut SourceId, LanguageId, Id, dan ReturnType, seperti yang disediakan dalam contoh berikut:
<Intrinsic Name="MyFunc" SourceId="a665fa54-6e7d-480e-a80b-1fc1202e9646" LanguageId="3a12d0b7-c26c-11d0-b442-00a0244a1dd2" Id="1000" ReturnType="double">
<Parameter Type="int" />
<Parameter Type="int" />
<Parameter Type="int" />
</Intrinsic>
Untuk mengimplementasikan fungsi, ekstensi debugger harus mengimplementasikan antarmuka IDkmIntrinsicFunctionEvaluator140, menggunakan filter LanguageId dan SourceId yang cocok dengan nilai yang sesuai dari elemen <Intrinsic> dalam file NatVis. Ketika fungsi dipanggil, panggilan diterjemahkan ke dalam metode Execute() komponen:
STDMETHOD(Execute)(
_In_ Evaluation::IL::DkmILExecuteIntrinsic* pExecuteIntrinsic,
_In_ Evaluation::DkmILContext* pILContext,
_In_ Evaluation::IL::DkmCompiledILInspectionQuery* pInspectionQuery,
_In_ const DkmArray<Evaluation::IL::DkmILEvaluationResult*>& Arguments,
_In_opt_ DkmReadOnlyCollection<Evaluation::DkmCompiledInspectionQuery*>* pSubroutines,
_Out_ DkmArray<Evaluation::IL::DkmILEvaluationResult*>* pResults,
_Out_ Evaluation::IL::DkmILFailureReason* pFailureReason
);
Komponen menerima byte dari setiap argumen melalui argumen Arguments. Jika fungsi yang dimaksud adalah fungsi anggota, penunjuk this menjadi yang pertama, diikuti oleh argumen eksplisit. Komponen harus mengembalikan hasil dengan mengalokasikan sebuah array dengan satu elemen di pResults, sehingga dapat menyimpan byte dari nilai yang dikembalikan.
Gunakan panduan berikut untuk mengimplementasikan fungsi:
Ini ilegal untuk "mencampur dan mencocokkan" dua bentuk implementasi. Artinya, Anda tidak dapat menyertakan ekspresi dan ID sumber.
Menentukan jenis pengembalian untuk implementasi berbasis ekspresi diizinkan, tetapi tidak diperlukan. Jika jenis pengembalian ditentukan, jenis ekspresi yang dikembalikan harus sama persis dengannya (tidak ada transmisi implisit yang diizinkan). Jika jenis pengembalian tidak ditentukan, jenis pengembalian disimpulkan dari ekspresi. Implementasi berbasis ekstensi apa pun harus menyatakan jenis pengembalian dalam file NatVis.
Panggilan non-rekursif ke fungsi intrinsik lainnya diizinkan. Rekursi tidak diperbolehkan.
Jika fungsi memiliki efek samping, Anda harus menentukan
SideEffect="true"dalam deklarasi. Ini ilegal bagi implementasi berbasis ekspresi memiliki efek samping dalam ekspresi tanpa menyatakan bahwa fungsi tersebut memiliki efek samping. Memanggil implementasi berbasis ekstensi untuk memiliki efek samping tanpa menyatakan fungsi karena memiliki efek samping adalah perilaku yang tidak ditentukan, dan harus dihindari.Fungsi intrinsik Varargs diperbolehkan. Untuk mendeklarasikan fungsi varargs, tentukan
Varargs="true"dalam deklarasi. Meskipun legal untuk implementasi berbasis ekspresi untuk mendeklarasikan fungsivararg, saat ini, hanya implementasi berbasis ekstensi yang memiliki cara untuk mengakses argumen variabel. Dengan implementasi berbasis ekstensi, fungsiExecute()menerima semua argumen yang benar-benar diteruskan, bukan hanya argumen yang dideklarasikan.Fungsi intrinsik yang menggunakan jenis class/struct/union sebagai jenis argumen tidak didukung. Mengembalikan tipe kelas/struct/union diperbolehkan. (Penunjuk atau referensi ke jenis kelas/struct/union OK sebagai jenis argumen).
Sesuaikan ikon untuk panggilan ke fungsi intrinsik.
Secara default, saat Anda memanggil fungsi intrinsik, ekspresi diberi ikon berlian merah muda di jendela Watch yang terkait dengan panggilan fungsi. Anda dapat mengambil alih perilaku ini dengan menentukan atribut Category menggunakan salah satu nilai berikut:
- Metode. Gunakan ikon berlian merah muda, biasanya digunakan dengan panggilan metode (default).
- Harta benda. Gunakan ikon kunci pas hitam, yang biasanya dikaitkan dengan atribut.
- Data. Gunakan ikon berlian biru, biasanya digunakan dengan data.
Dengan menggabungkan fungsi intrinsik dengan elemen <Item>, dimungkinkan untuk membuat berkas NatVis di mana ekspresi item memiliki ikon properti berupa kunci pas:
<Type Name="MyClass">
<Intrinsic Name="GetValue" ReturnType="int" Expression="m_value" Category="Property" />
<Expand>
<Item Name="Value">this->GetValue()</Item>
</Expand>
</Type>
Nota
Menempatkan pilihan ikon pada tingkat fungsi, bukan tingkat <Item>, menghindari masalah di mana kustomisasi ikon hilang saat nama lengkap dievaluasi. Karena nama lengkap mencakup panggilan fungsi, ia memiliki kustomisasi ikon yang sama dengan <Item> itu sendiri.