Saya selalu tidak yakin, apa arti kata kunci pembatasan dalam C ++?
Apakah ini berarti dua atau lebih pointer yang diberikan pada fungsi tidak tumpang tindih? Apa lagi artinya?
c++
restrict-qualifier
Tikar
sumber
sumber
restrict
adalah kata kunci c99. Ya, Rpbert S. Barnes, saya tahu sebagian besar penyusun mendukung__restrict__
. Anda akan mencatat bahwa apa pun dengan garis bawah ganda adalah, menurut definisi, implementasi spesifik dan karenanya BUKAN C ++ , tetapi merupakan versi spesifik kompilator.#warning
arahan umum , atau makro tanda tangan fungsi (__PRETTY_FUNCTION__
pada GCC,__FUNCSIG__
pada MSVC, dll.).restrict
tidak dianggap sebagai kata kunci C ++ (lihat en.cppreference.com/w/cpp/keyword ), dan pada kenyataannya, satu-satunya penyebutanrestrict
dalam standar C ++ 11 (lihat open-std.org/jtc1/sc22/wg21 /docs/papers/2012/n3337.pdf , salinan FDIS dengan perubahan editorial kecil, §17.2 [library.c], halaman PDF 413) menyatakan bahwa:restrict
harus dihilangkan dari (dikecualikan dari, ditinggalkan dari) tanda tangan dan semantik fungsi pustaka C ketika fungsi-fungsi tersebut dimasukkan dalam pustaka standar C ++. Atau dengan kata lain, saya menyatakan fakta yang mengatakan bahwa jika tanda tangan fungsi pustaka standar C berisirestrict
dalam C,restrict
kata kunci harus dihapus dari tanda tangan setara C ++.Jawaban:
Dalam makalahnya, Memory Optimization , Christer Ericson mengatakan bahwa sementara
restrict
ini belum menjadi bagian dari standar C ++, ia didukung oleh banyak kompiler dan ia merekomendasikan penggunaannya ketika tersedia:Dalam kompiler C ++ yang mendukungnya mungkin harus berperilaku sama seperti pada C.
Lihat posting SO ini untuk perincian: Penggunaan realistis kata kunci 'pembatasan' C99?
Butuh setengah jam untuk membaca kertas Ericson, itu menarik dan sepadan dengan waktu.
Edit
Saya juga menemukan bahwa kompiler AIX C / C ++
__restrict__
IBM mendukung kata kunci .g ++ juga sepertinya mendukung hal ini karena program berikut mengkompilasi dengan bersih di g ++:
Saya juga menemukan artikel yang bagus tentang penggunaan
restrict
:Demistifying The Restrict Keyword
Edit2
Saya menemukan artikel yang secara khusus membahas penggunaan pembatasan dalam program C ++:
Muat-tekan-toko dan kata kunci __restrict
Selain itu, Microsoft Visual C ++ juga mendukung
__restrict
kata kunci .sumber
#ifndef __GNUC__
#define __restrict__ /* no-op */
atau serupa. Dan mendefinisikannya__restrict
jika_MSC_VER
didefinisikan.Seperti yang dikatakan orang lain, jika tidak ada artinya pada C ++ 14 , jadi mari kita pertimbangkan
__restrict__
ekstensi GCC yang melakukan hal yang sama dengan C99restrict
.C99
restrict
mengatakan bahwa dua petunjuk tidak dapat menunjuk ke wilayah memori yang tumpang tindih. Penggunaan paling umum adalah untuk argumen fungsi.Ini membatasi bagaimana fungsi dapat dipanggil, tetapi memungkinkan untuk lebih kompilasi optimasi.
Jika penelepon tidak mengikuti
restrict
kontrak, perilaku tidak terdefinisi.The C99 N1256 rancangan 6.7.3 / 7 "Jenis kualifikasi" mengatakan:
dan 6.7.3.1 "Definisi formal pembatasan" memberikan detail yang mengerikan.
Kemungkinan pengoptimalan
The Wikipedia Contoh yang sangat mencerahkan.
Ini jelas menunjukkan bagaimana memungkinkan untuk menyimpan satu instruksi perakitan .
Tanpa batasan:
Perakitan semu:
Dengan batasan:
Perakitan semu:
Apakah GCC benar-benar melakukannya?
g++
4.8 Linux x86-64:Dengan
-O0
, mereka sama.Dengan
-O3
:Untuk yang belum tahu, konvensi pemanggilan adalah:
rdi
= parameter pertamarsi
= parameter keduardx
= parameter ketigaOutput GCC bahkan lebih jelas daripada artikel wiki: 4 instruksi vs 3 instruksi.
Array
Sejauh ini kami memiliki penghematan instruksi tunggal, tetapi jika pointer mewakili array yang akan dilewati, kasus penggunaan umum, maka banyak instruksi dapat disimpan, seperti yang disebutkan oleh supercat dan michael .
Pertimbangkan misalnya:
Karena itu
restrict
, kompiler pintar (atau manusia), dapat mengoptimalkannya untuk:Yang berpotensi jauh lebih efisien karena dapat dioptimalkan perakitan pada implementasi libc yang layak (seperti glibc) Apakah lebih baik menggunakan std :: memcpy () atau std :: copy () dalam hal kinerja? , mungkin dengan instruksi SIMD .
Tanpa, batasi, optimasi ini tidak dapat dilakukan, misalnya pertimbangkan:
Kemudian
for
versi membuat:sedangkan
memset
versi membuat:Apakah GCC benar-benar melakukannya?
GCC 5.2.1.Linux x86-64 Ubuntu 15.10:
Dengan
-O0
, keduanya sama.Dengan
-O3
:dengan batasan:
Dua
memset
panggilan seperti yang diharapkan.tanpa batasan: tidak ada panggilan stdlib, hanya loop lebar iterasi 16 terbuka yang saya tidak ingin mereproduksi di sini :-)
Saya belum memiliki kesabaran untuk membandingkan mereka, tetapi saya percaya bahwa versi pembatasan akan lebih cepat.
Aturan aliasing yang ketat
Kata
restrict
kunci hanya memengaruhi pointer dari tipe yang kompatibel (misalnya duaint*
) karena aturan aliasing yang ketat mengatakan bahwa aliasing tipe yang tidak kompatibel adalah perilaku yang tidak terdefinisi secara default, sehingga kompiler dapat menganggap itu tidak terjadi dan mengoptimalkannya.Lihat: Apa aturan aliasing yang ketat?
Apakah ini berfungsi untuk referensi?
Menurut dokumen GCC, ia melakukannya: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Restricted-Pointers.html dengan sintaks:
Bahkan ada versi untuk
this
fungsi anggota:sumber
-fno-strict-aliasing
, makarestrict
seharusnya tidak ada perbedaan antara pointer dari tipe yang sama atau tipe yang berbeda, bukan? (saya merujuk ke "Batasan kata kunci hanya memengaruhi pointer dari jenis yang kompatibel")restrict
memang berarti sesuatu dalam C ++. Jika Anda memanggil fungsi pustaka C denganrestrict
parameter dari program C ++, Anda harus mematuhi implikasinya. Pada dasarnya, jikarestrict
digunakan dalam C library API, itu berarti sesuatu bagi siapa saja yang memanggilnya dari bahasa apa pun, termasuk FFI dinamis dari Lisp.Tidak ada. Itu ditambahkan ke standar C99.
sumber
restrict
sebagai kata kunci. Karenanya jawaban saya benar. Apa yang Anda gambarkan adalah penerapan perilaku spesifik dan sesuatu yang tidak seharusnya Anda andalkan.Ini adalah proposal asli untuk menambahkan kata kunci ini. Seperti yang ditunjukkan secara langsung, ini adalah fitur C99 ; tidak ada hubungannya dengan C ++.
sumber
__restrict__
kata kunci yang identik sejauh yang saya tahu.restrict
. Perilaku program C ++ menjadi tidak terdefinisi jika melanggar batasan yang disiratkan olehrestrict
.restrict
kata kunci. Tentu saja jika Anda meneruskan pointer alias ke fungsi C yang menyatakan mereka dibatasi (yang dapat Anda lakukan dari C ++ atau C) maka itu tidak terdefinisi, tapi itu pada Anda.restrict
. Perilaku program C ++ menjadi tidak terdefinisi jika melanggar batasan yang dinyatakan oleh pembatasan. Tapi ini sebenarnya tidak ada hubungannya dengan C ++, karena itu "pada Anda".Tidak ada kata kunci seperti itu di C ++. Daftar kata kunci C ++ dapat ditemukan di bagian 2.11 / 1 dari standar bahasa C ++.
restrict
adalah kata kunci dalam versi C99 bahasa C dan bukan dalam C ++.sumber
__restrict__
kata kunci yang identik sejauh yang saya tahu.Karena file header dari beberapa pustaka C menggunakan kata kunci, bahasa C ++ harus melakukan sesuatu tentang itu .. minimal, mengabaikan kata kunci, jadi kami tidak perlu # mendefinisikan kata kunci ke makro kosong untuk menekan kata kunci .
sumber
extern C
deklarasi, atau dengan itu diam-diam dijatuhkan, seperti halnya dengan kompiler A / C ++ AIX, yang alih-alih menangani__rerstrict__
kata kunci. Kata kunci itu juga didukung di bawah gcc sehingga kode tersebut akan dikompilasi di bawah g ++.