Saya akan menebak bahwa tanpa pengoptimalan canggih yang dapat mendeteksi itu tidak akan pernah berubah dalam perulangan, maka ya. Terbaik untuk dikompilasi, dan lihat perakitan untuk melihat.
MerickOWA
6
Itu tergantung pada kompiler, pada tingkat optimasi dan pada apa yang Anda (mungkin) lakukan ssdi dalam loop.
Hristo Iliev
4
Jika kompilator dapat membuktikan bahwa ssia tidak pernah dimodifikasi, ia dapat mengeluarkan komputasi dari loop.
Daniel Fischer
10
@ Mike: "memerlukan analisis waktu kompilasi dari apa yang sebenarnya dilakukan strlen" - strlen mungkin adalah intrinsik, dalam hal ini pengoptimal tahu apa yang dilakukannya.
Steve Jessop
3
@MikeSeymour: Tidak mungkin, mungkin juga tidak. strlen didefinisikan oleh standar bahasa C, dan namanya dicadangkan untuk penggunaan yang ditentukan oleh bahasa tersebut, sehingga program tidak bebas untuk menyediakan definisi yang berbeda. Kompilator dan pengoptimal berhak menganggap strlen hanya bergantung pada inputnya dan tidak mengubahnya atau status global apa pun. Tantangan untuk pengoptimalan di sini adalah menentukan bahwa memori yang ditunjukkan oleh ss tidak diubah oleh kode apa pun di dalam loop. Itu sepenuhnya dapat dilakukan dengan kompiler saat ini, bergantung pada kode spesifik.
Eric Postpischil
Jawaban:
138
Ya, strlen()akan dievaluasi pada setiap iterasi. Ada kemungkinan bahwa, dalam keadaan ideal, pengoptimal mungkin dapat menyimpulkan bahwa nilainya tidak akan berubah, tetapi saya pribadi tidak akan bergantung pada itu.
Saya akan melakukan sesuatu seperti
for(int i =0, n = strlen(ss); i < n;++i)
atau mungkin
for(int i =0; ss[i];++i)
selama string tidak akan berubah panjang selama iterasi. Jika mungkin, Anda harus menelepon strlen()setiap kali, atau menanganinya melalui logika yang lebih rumit.
Jika Anda tahu Anda tidak memanipulasi string, yang kedua jauh lebih disukai karena pada dasarnya itulah loop yang akan dilakukan strlenolehnya.
mlibby
26
@alk: Jika string mungkin dipersingkat, maka keduanya salah.
Mike Seymour
3
@alk: jika Anda mengubah string, perulangan for mungkin bukan cara terbaik untuk mengulang setiap karakter. Menurut saya, loop sementara lebih langsung dan lebih mudah untuk mengelola penghitung indeks.
mlibby
2
keadaan yang ideal mencakup kompilasi dengan GCC di bawah linux, di mana strlenditandai __attribute__((pure))mengizinkan kompiler untuk memanggil banyak panggilan. Atribut GCC
David Rodríguez - dribeas
6
Versi kedua adalah bentuk yang ideal dan paling idiomatis. Ini memungkinkan Anda untuk melewatkan string hanya sekali daripada dua kali, yang akan memiliki kinerja yang jauh lebih baik (terutama koherensi cache) untuk string yang panjang.
R .. GitHub STOP HELPING ICE
14
Ya, setiap kali Anda menggunakan loop. Maka itu akan setiap kali menghitung panjang string. jadi gunakan seperti ini:
char str[30];for(int i =0; str[i]!='\0'; i++){//Something;}
Pada kode di atas str[i]hanya memverifikasi satu karakter tertentu dalam string di lokasi isetiap kali loop memulai siklus, sehingga akan memakan lebih sedikit memori dan lebih efisien.
Pada kode di bawah ini setiap kali loop berjalan strlenakan menghitung panjang keseluruhan string yang kurang efisien, membutuhkan lebih banyak waktu dan membutuhkan lebih banyak memori.
char str[];for(int i =0; i < strlen(str); i++){//Something;}
Saya setuju dengan "[itu] lebih efisien", tetapi menggunakan lebih sedikit memori? Satu-satunya perbedaan penggunaan memori yang dapat saya pikirkan akan berada di tumpukan panggilan selama strlenpanggilan, dan jika Anda menjalankannya sesak itu, Anda mungkin harus berpikir untuk memilih beberapa panggilan fungsi lainnya juga ...
CVn
@ MichaelKjörling Jika Anda menggunakan "strlen", maka dalam satu loop harus memindai seluruh string setiap kali loop berjalan, sedangkan dalam kode di atas "str [ix]", itu hanya memindai satu elemen selama setiap siklus loop yang lokasinya diwakili oleh "ix". Jadi dibutuhkan lebih sedikit memori daripada "strlen".
kodeDEXTER
1
Saya tidak yakin itu masuk akal, sebenarnya. Implementasi strlen yang sangat naif akan menjadi sesuatu int strlen(char *s) { int len = 0; while(s[len] != '\0') len++; return len; }yang persis seperti yang Anda lakukan dalam kode dalam jawaban Anda. Saya tidak berargumen bahwa mengulang string sekali daripada dua kali lebih efisien waktu , tetapi saya tidak melihat satu atau yang lain menggunakan lebih banyak atau lebih sedikit memori. Atau apakah Anda mengacu pada variabel yang digunakan untuk menahan panjang string?
CVn
@ MichaelKjörling Silakan lihat kode yang diedit di atas dan tautannya. Dan untuk memori- setiap kali loop berjalan, setiap nilai yang diiterasi disimpan dalam memori dan dalam kasus 'strlen' karena menghitung seluruh string berulang kali, diperlukan lebih banyak memori untuk disimpan. dan juga karena tidak seperti Java, C ++ tidak memiliki "Pengumpul Sampah". Maka saya bisa salah juga. lihat tautan mengenai tidak adanya "Pengumpul Sampah" di C ++.
codeDEXTER
1
@ aashis2s Kurangnya pengumpul sampah hanya berperan saat membuat objek di heap. Objek di tumpukan akan dihancurkan segera setelah cakupan dan berakhir.
Ikke
9
Kompiler yang baik mungkin tidak menghitungnya setiap saat, tetapi menurut saya Anda tidak dapat memastikan, bahwa setiap kompiler melakukannya.
Selain itu, kompilator harus tahu, itu strlen(ss)tidak berubah. Ini hanya benar jika sstidak diubah dalam forloop.
Misalnya, jika Anda menggunakan fungsi hanya-baca di ssdalam forperulangan tetapi tidak mendeklarasikan ss-parameter sebagai const, kompilator bahkan tidak dapat mengetahui bahwa sstidak diubah dalam perulangan dan harus menghitung strlen(ss)di setiap iterasi.
+1: Tidak hanya sstidak boleh diubah di forloop; itu tidak boleh dapat diakses dari dan diubah oleh fungsi apa pun yang dipanggil dalam loop (baik karena diteruskan sebagai argumen, atau karena variabel global atau variabel cakupan file). Kualifikasi konstitusi juga bisa menjadi faktor.
Jonathan Leffler
4
Saya rasa sangat tidak mungkin kompilator bisa mengetahui bahwa 'ss' tidak berubah. Mungkin ada petunjuk tersesat yang mengarah ke memori di dalam 'ss' yang tidak diketahui oleh kompiler yang dapat mengubah 'ss'
MerickOWA
Jonathan benar, string const lokal mungkin merupakan satu-satunya cara bagi kompilator untuk yakin bahwa tidak ada cara untuk 'ss' berubah.
MerickOWA
2
@MerickOWA: memang, itulah salah satu hal yang restrictada di C99.
Steve Jessop
4
Mengenai para terakhir Anda: jika Anda memanggil fungsi read-only ssdi for-loop, bahkan jika parameternya dideklarasikan const char*, compiler masih perlu menghitung ulang panjangnya kecuali jika (a) ia tahu bahwa ssmenunjuk ke objek const, sebagai lawan hanya menjadi pointer-to-const, atau (b) itu dapat menyebariskan fungsi atau melihat bahwa itu hanya-baca. Mengambil const char*parameter bukanlah janji untuk tidak mengubah data yang ditunjuk, karena valid untuk mentransmisikan char*dan memodifikasi asalkan objek yang dimodifikasi bukan const dan bukan literal string.
Steve Jessop
4
Jika ssadalah tipe const char *dan Anda tidak membuang semua kebutuhan constdalam loop, kompilator mungkin hanya memanggil strlensekali, jika pengoptimalan dihidupkan. Tapi ini jelas bukan perilaku yang bisa diandalkan.
Anda harus menyimpan strlenhasilnya dalam sebuah variabel dan menggunakan variabel ini dalam perulangan. Jika Anda tidak ingin membuat variabel tambahan, tergantung pada apa yang Anda lakukan, Anda mungkin bisa melakukannya dengan membalik loop untuk mengulang ke belakang.
for(auto i = strlen(s); i >0;--i ){// do whatever// remember value of s[strlen(s)] is the terminating NULL character}
Ini adalah kesalahan untuk menelepon strlensama sekali. Ulangi sampai Anda mencapai akhir.
R .. GitHub STOP HELPING ICE
i > 0? Bukankah seharusnya itu ada di i >= 0sini? Secara pribadi, saya juga akan mulai strlen(s) - 1jika mengulangi string ke belakang, maka pengakhiran \0tidak memerlukan pertimbangan khusus.
CVn
2
@ MichaelKjörling i >= 0hanya berfungsi jika Anda menginisialisasi ke strlen(s) - 1, tetapi kemudian jika Anda memiliki string dengan panjang nol, nilai awal kurang mengalir
Praetorian
@ Prætorian, poin bagus pada string panjang nol. Saya tidak mempertimbangkan kasus itu ketika saya menulis komentar saya. Apakah C ++ mengevaluasi i > 0ekspresi pada entri pengulangan awal? Jika tidak, maka Anda benar, case dengan panjang nol pasti akan memutuskan loop. Jika ya, Anda "cukup" mendapatkan tanda i== -1 <0 sehingga tidak ada entri loop jika kondisionalnya i >= 0.
CVn
@ MichaelKjörling Ya, kondisi keluar dievaluasi sebelum menjalankan loop untuk pertama kalinya. strlenJenis kembalian tidak bertanda tangan, sehingga (strlen(s)-1) >= 0mengevaluasi true untuk string panjang nol.
Praetorian
3
Secara formal ya, strlen()diharapkan dipanggil untuk setiap iterasi.
Bagaimanapun saya tidak ingin meniadakan kemungkinan adanya beberapa optimasi kompilator pintar, yang akan mengoptimalkan panggilan berurutan ke strlen () setelah yang pertama.
Kode predikat secara keseluruhan akan dieksekusi pada setiap iterasi forloop. Untuk mengingat hasil strlen(ss)panggilan, kompilator perlu mengetahui hal itu setidaknya
Fungsinya strlenbebas efek samping
Memori yang ditunjukkan oleh sstidak berubah selama durasi loop
Kompilator tidak mengetahui salah satu dari hal-hal ini dan karenanya tidak dapat dengan aman membuat memo hasil panggilan pertama
Ia bisa mengetahui hal-hal tersebut dengan analisis statis, tapi saya pikir maksud Anda adalah bahwa analisis tersebut saat ini tidak diterapkan di kompiler C ++, ya?
GManNickG
@GManNickG pasti bisa membuktikan # 1 tetapi # 2 lebih sulit. Untuk satu utas ya itu pasti bisa membuktikannya tetapi tidak untuk lingkungan multi-utas.
JaredPar
1
Mungkin saya keras kepala tapi saya pikir nomor dua juga mungkin dalam lingkungan multithread, tapi jelas bukan tanpa sistem inferensi yang sangat kuat. Hanya merenung di sini; pasti di luar cakupan kompiler C ++ saat ini.
GManNickG
@GManNickG saya rasa tidak mungkin meskipun dalam C / C ++. Saya dapat dengan mudah menyimpan alamat sske dalam size_tatau membaginya di antara beberapa bytenilai. Utas licik saya kemudian bisa saja menulis byte ke alamat itu dan kompiler akan tahu cara memahami yang terkait dengannya ss.
JaredPar
1
@JaredPar: Maaf bang, Anda dapat mengklaim itu int a = 0; do_something(); printf("%d",a);tidak dapat dioptimalkan, atas dasar yang do_something()dapat melakukan hal int yang tidak diinisialisasi, atau dapat merayapi kembali tumpukan dan memodifikasi dengan asengaja. Faktanya, gcc 4.5 mengoptimalkannya do_something(); printf("%d",0);dengan -O3
Steve Jessop
2
Iya . strlen akan dihitung setiap kali saya meningkat.
Jika Anda tidak mengubah ss dengan in loop berarti itu tidak akan mempengaruhi logika jika tidak maka akan mempengaruhi.
Lebih aman menggunakan kode berikut.
int length = strlen(ss);for(int i =0; i < length ;++ i ){// blabla}
Ya, perusahaan strlen(ss)akan menghitung panjang pada setiap iterasi. Jika Anda meningkatkan ssdengan cara tertentu dan juga meningkatkan i; akan ada putaran tak terbatas.
Ya, strlen()fungsinya dipanggil setiap kali loop dievaluasi.
Jika Anda ingin meningkatkan efisiensi maka selalu ingat untuk menyimpan semuanya di variabel lokal ... Ini akan memakan waktu tetapi sangat berguna ..
Anda dapat menggunakan kode seperti di bawah ini:
String str="ss";int l = strlen(str);for(int i =0; i < l ; i++){// blablabla}
YA, dengan kata sederhana. Dan ada sedikit kata tidak dalam kondisi langka di mana kompilator menginginkannya, sebagai langkah pengoptimalan jika ternyata tidak ada perubahan sssama sekali. Tetapi dalam kondisi aman Anda harus menganggapnya YA. Ada beberapa situasi seperti in multithreadeddan event driven program, ini mungkin bermasalah jika Anda menganggapnya TIDAK. Lakukan dengan aman karena tidak akan terlalu meningkatkan kompleksitas program.
Saya pikir melakukan modifikasi khusus itu tidak pernah mengubah panjang ss, hanya isinya, jadi kompiler (yang benar-benar pintar) masih bisa mengoptimalkan strlen.
Kondisi loop mengevaluasi setelah setiap pengulangan, sebelum mengulang loop.
Juga berhati-hatilah dengan jenis yang Anda gunakan untuk menangani panjang string. itu harus size_tyang telah didefinisikan seperti unsigned intdi stdio. membandingkan dan mentransmisikannya intmungkin menyebabkan beberapa masalah kerentanan yang serius.
well, saya perhatikan bahwa seseorang mengatakan bahwa ini dioptimalkan secara default oleh kompiler modern "pintar". Dengan cara melihat hasil tanpa pengoptimalan. Saya mencoba: Kode C Minimal:
Kompiler saya: g ++ (Ubuntu / Linaro 4.6.3-1ubuntu5) 4.6.3
Perintah untuk pembuatan kode assembly: g ++ -S -masm = intel test.cpp
Gotten assembly code at the output:...
L3:
mov DWORD PTR [esp],97
call putchar
add DWORD PTR [esp+40],1.L2:
THIS LOOP IS HERE
**<b>mov ebx, DWORD PTR [esp+40]
mov eax, DWORD PTR [esp+44]
mov DWORD PTR [esp+28],-1
mov edx, eax
mov eax,0
mov ecx, DWORD PTR [esp+28]
mov edi, edx
repnz scasb</b>**
AS YOU CAN SEE it's done every time
mov eax, ecx
not eax
sub eax, 1
cmp ebx, eax
setb al
test al, al
jne .L3
mov eax, 0
.....
Saya akan enggan untuk mempercayai kompiler yang mencoba mengoptimalkannya kecuali alamat stringnya restrict -qualified. Meskipun ada beberapa kasus di mana pengoptimalan seperti itu akan sah, upaya yang diperlukan untuk mengidentifikasi kasus seperti itu secara andal tanpa adanya restrictkemauan, dengan ukuran yang wajar, hampir pasti melebihi manfaatnya. Jika alamat string memiliki const restrictkualifikasi, bagaimanapun, itu akan cukup untuk membenarkan pengoptimalan tanpa harus melihat yang lain.
supercat
0
Menguraikan jawaban Prætorian, saya merekomendasikan yang berikut ini:
for(auto i = strlen(s)-1; i >0;--i ){foo(s[i-1];}
autokarena Anda tidak ingin peduli tentang tipe mana yang dikembalikan strlen. Kompiler C ++ 11 (misalnya gcc -std=c++0x, tidak sepenuhnya C ++ 11 tetapi tipe otomatis berfungsi) akan melakukannya untuk Anda.
i = strlen(s)karena Anda ingin membandingkan 0(lihat di bawah)
i > 0 karena perbandingan dengan 0 (sedikit) lebih cepat dibandingkan dengan angka lainnya.
kelemahannya adalah Anda harus menggunakan i-1untuk mengakses karakter string.
ss
di dalam loop.ss
ia tidak pernah dimodifikasi, ia dapat mengeluarkan komputasi dari loop.Jawaban:
Ya,
strlen()
akan dievaluasi pada setiap iterasi. Ada kemungkinan bahwa, dalam keadaan ideal, pengoptimal mungkin dapat menyimpulkan bahwa nilainya tidak akan berubah, tetapi saya pribadi tidak akan bergantung pada itu.Saya akan melakukan sesuatu seperti
atau mungkin
selama string tidak akan berubah panjang selama iterasi. Jika mungkin, Anda harus menelepon
strlen()
setiap kali, atau menanganinya melalui logika yang lebih rumit.sumber
strlen
olehnya.strlen
ditandai__attribute__((pure))
mengizinkan kompiler untuk memanggil banyak panggilan. Atribut GCCYa, setiap kali Anda menggunakan loop. Maka itu akan setiap kali menghitung panjang string. jadi gunakan seperti ini:
Pada kode di atas
str[i]
hanya memverifikasi satu karakter tertentu dalam string di lokasii
setiap kali loop memulai siklus, sehingga akan memakan lebih sedikit memori dan lebih efisien.Lihat Tautan ini untuk informasi lebih lanjut.
Pada kode di bawah ini setiap kali loop berjalan
strlen
akan menghitung panjang keseluruhan string yang kurang efisien, membutuhkan lebih banyak waktu dan membutuhkan lebih banyak memori.sumber
strlen
panggilan, dan jika Anda menjalankannya sesak itu, Anda mungkin harus berpikir untuk memilih beberapa panggilan fungsi lainnya juga ...int strlen(char *s) { int len = 0; while(s[len] != '\0') len++; return len; }
yang persis seperti yang Anda lakukan dalam kode dalam jawaban Anda. Saya tidak berargumen bahwa mengulang string sekali daripada dua kali lebih efisien waktu , tetapi saya tidak melihat satu atau yang lain menggunakan lebih banyak atau lebih sedikit memori. Atau apakah Anda mengacu pada variabel yang digunakan untuk menahan panjang string?Kompiler yang baik mungkin tidak menghitungnya setiap saat, tetapi menurut saya Anda tidak dapat memastikan, bahwa setiap kompiler melakukannya.
Selain itu, kompilator harus tahu, itu
strlen(ss)
tidak berubah. Ini hanya benar jikass
tidak diubah dalamfor
loop.Misalnya, jika Anda menggunakan fungsi hanya-baca di
ss
dalamfor
perulangan tetapi tidak mendeklarasikanss
-parameter sebagaiconst
, kompilator bahkan tidak dapat mengetahui bahwass
tidak diubah dalam perulangan dan harus menghitungstrlen(ss)
di setiap iterasi.sumber
ss
tidak boleh diubah difor
loop; itu tidak boleh dapat diakses dari dan diubah oleh fungsi apa pun yang dipanggil dalam loop (baik karena diteruskan sebagai argumen, atau karena variabel global atau variabel cakupan file). Kualifikasi konstitusi juga bisa menjadi faktor.restrict
ada di C99.ss
di for-loop, bahkan jika parameternya dideklarasikanconst char*
, compiler masih perlu menghitung ulang panjangnya kecuali jika (a) ia tahu bahwass
menunjuk ke objek const, sebagai lawan hanya menjadi pointer-to-const, atau (b) itu dapat menyebariskan fungsi atau melihat bahwa itu hanya-baca. Mengambilconst char*
parameter bukanlah janji untuk tidak mengubah data yang ditunjuk, karena valid untuk mentransmisikanchar*
dan memodifikasi asalkan objek yang dimodifikasi bukan const dan bukan literal string.Jika
ss
adalah tipeconst char *
dan Anda tidak membuang semua kebutuhanconst
dalam loop, kompilator mungkin hanya memanggilstrlen
sekali, jika pengoptimalan dihidupkan. Tapi ini jelas bukan perilaku yang bisa diandalkan.Anda harus menyimpan
strlen
hasilnya dalam sebuah variabel dan menggunakan variabel ini dalam perulangan. Jika Anda tidak ingin membuat variabel tambahan, tergantung pada apa yang Anda lakukan, Anda mungkin bisa melakukannya dengan membalik loop untuk mengulang ke belakang.sumber
strlen
sama sekali. Ulangi sampai Anda mencapai akhir.i > 0
? Bukankah seharusnya itu ada dii >= 0
sini? Secara pribadi, saya juga akan mulaistrlen(s) - 1
jika mengulangi string ke belakang, maka pengakhiran\0
tidak memerlukan pertimbangan khusus.i >= 0
hanya berfungsi jika Anda menginisialisasi kestrlen(s) - 1
, tetapi kemudian jika Anda memiliki string dengan panjang nol, nilai awal kurang mengaliri > 0
ekspresi pada entri pengulangan awal? Jika tidak, maka Anda benar, case dengan panjang nol pasti akan memutuskan loop. Jika ya, Anda "cukup" mendapatkan tandai
== -1 <0 sehingga tidak ada entri loop jika kondisionalnyai >= 0
.strlen
Jenis kembalian tidak bertanda tangan, sehingga(strlen(s)-1) >= 0
mengevaluasi true untuk string panjang nol.Secara formal ya,
strlen()
diharapkan dipanggil untuk setiap iterasi.Bagaimanapun saya tidak ingin meniadakan kemungkinan adanya beberapa optimasi kompilator pintar, yang akan mengoptimalkan panggilan berurutan ke strlen () setelah yang pertama.
sumber
Kode predikat secara keseluruhan akan dieksekusi pada setiap iterasi
for
loop. Untuk mengingat hasilstrlen(ss)
panggilan, kompilator perlu mengetahui hal itu setidaknyastrlen
bebas efek sampingss
tidak berubah selama durasi loopKompilator tidak mengetahui salah satu dari hal-hal ini dan karenanya tidak dapat dengan aman membuat memo hasil panggilan pertama
sumber
ss
ke dalamsize_t
atau membaginya di antara beberapabyte
nilai. Utas licik saya kemudian bisa saja menulis byte ke alamat itu dan kompiler akan tahu cara memahami yang terkait dengannyass
.int a = 0; do_something(); printf("%d",a);
tidak dapat dioptimalkan, atas dasar yangdo_something()
dapat melakukan hal int yang tidak diinisialisasi, atau dapat merayapi kembali tumpukan dan memodifikasi dengana
sengaja. Faktanya, gcc 4.5 mengoptimalkannyado_something(); printf("%d",0);
dengan -O3Iya . strlen akan dihitung setiap kali saya meningkat.
Jika Anda tidak mengubah ss dengan in loop berarti itu tidak akan mempengaruhi logika jika tidak maka akan mempengaruhi.
Lebih aman menggunakan kode berikut.
sumber
Ya, perusahaan
strlen(ss)
akan menghitung panjang pada setiap iterasi. Jika Anda meningkatkanss
dengan cara tertentu dan juga meningkatkani
; akan ada putaran tak terbatas.sumber
Ya,
strlen()
fungsinya dipanggil setiap kali loop dievaluasi.Jika Anda ingin meningkatkan efisiensi maka selalu ingat untuk menyimpan semuanya di variabel lokal ... Ini akan memakan waktu tetapi sangat berguna ..
Anda dapat menggunakan kode seperti di bawah ini:
sumber
Ya,
strlen(ss)
akan dihitung setiap kali kode dijalankan.sumber
Tidak umum saat ini tetapi 20 tahun yang lalu pada platform 16 bit, saya merekomendasikan ini:
Bahkan jika kompiler Anda tidak terlalu pintar dalam pengoptimalan, kode di atas dapat menghasilkan kode assembly yang bagus.
sumber
Iya. Pengujian tidak mengetahui bahwa ss tidak berubah di dalam loop. Jika Anda tahu bahwa itu tidak akan berubah maka saya akan menulis:
sumber
Ah, itu akan, bahkan dalam keadaan ideal, sialan!
Mulai hari ini (Januari 2018), dan gcc 7.3 dan clang 5.0, jika Anda mengompilasi:
Jadi kita punya:
ss
adalah penunjuk konstan.ss
ditandai__restrict__
ss
(yah, kecuali jika melanggar__restrict__
).dan tetap saja , kedua kompiler mengeksekusi
strlen()
setiap iterasi loop tersebut . Luar biasa.Ini juga berarti kiasan / angan-angan dari @Praetorian dan @JaredPar tidak berjalan dengan baik.
sumber
YA, dengan kata sederhana. Dan ada sedikit kata tidak dalam kondisi langka di mana kompilator menginginkannya, sebagai langkah pengoptimalan jika ternyata tidak ada perubahan
ss
sama sekali. Tetapi dalam kondisi aman Anda harus menganggapnya YA. Ada beberapa situasi seperti inmultithreaded
dan event driven program, ini mungkin bermasalah jika Anda menganggapnya TIDAK. Lakukan dengan aman karena tidak akan terlalu meningkatkan kompleksitas program.sumber
Iya.
strlen()
dihitung setiap saati
meningkat dan tidak dioptimalkan.Kode di bawah ini menunjukkan mengapa kompilator tidak harus dioptimalkan
strlen()
.sumber
strlen
.Kami dapat dengan mudah mengujinya:
Kondisi loop mengevaluasi setelah setiap pengulangan, sebelum mengulang loop.
Juga berhati-hatilah dengan jenis yang Anda gunakan untuk menangani panjang string. itu harus
size_t
yang telah didefinisikan sepertiunsigned int
di stdio. membandingkan dan mentransmisikannyaint
mungkin menyebabkan beberapa masalah kerentanan yang serius.sumber
well, saya perhatikan bahwa seseorang mengatakan bahwa ini dioptimalkan secara default oleh kompiler modern "pintar". Dengan cara melihat hasil tanpa pengoptimalan. Saya mencoba:
Kode C Minimal:
Kompiler saya: g ++ (Ubuntu / Linaro 4.6.3-1ubuntu5) 4.6.3
Perintah untuk pembuatan kode assembly: g ++ -S -masm = intel test.cpp
sumber
restrict
-qualified. Meskipun ada beberapa kasus di mana pengoptimalan seperti itu akan sah, upaya yang diperlukan untuk mengidentifikasi kasus seperti itu secara andal tanpa adanyarestrict
kemauan, dengan ukuran yang wajar, hampir pasti melebihi manfaatnya. Jika alamat string memilikiconst restrict
kualifikasi, bagaimanapun, itu akan cukup untuk membenarkan pengoptimalan tanpa harus melihat yang lain.Menguraikan jawaban Prætorian, saya merekomendasikan yang berikut ini:
auto
karena Anda tidak ingin peduli tentang tipe mana yang dikembalikan strlen. Kompiler C ++ 11 (misalnyagcc -std=c++0x
, tidak sepenuhnya C ++ 11 tetapi tipe otomatis berfungsi) akan melakukannya untuk Anda.i = strlen(s)
karena Anda ingin membandingkan0
(lihat di bawah)i > 0
karena perbandingan dengan 0 (sedikit) lebih cepat dibandingkan dengan angka lainnya.kelemahannya adalah Anda harus menggunakan
i-1
untuk mengakses karakter string.sumber