Saat menggunakan header C di C ++, haruskah kita menggunakan fungsi dari std :: atau namespace global?

113

C agak, tidak persis, bagian dari C ++. Jadi kita dapat menggunakan sebagian besar fungsi / header C di C ++ dengan mengubah nama sedikit ( stdio.hmenjadi cstdio, stdlib.hmenjadi cstdlib).

Pertanyaan saya sebenarnya semacam semantik. Dalam kode C ++ (menggunakan versi terbaru dari kompiler GCC), saya dapat memanggil printf("Hello world!");dan std::printf("Hello world!");bekerja persis sama. Dan dalam referensi yang saya gunakan juga muncul sebagai std::printf("Hello world!");.

Pertanyaan saya adalah, apakah ini lebih disukai untuk digunakan std::printf();dalam C ++? Apakah ada bedanya?

DeiDei
sumber
17
Jika suatu hari mereka mengamanatkan pembuangan Csimbol perpustakaan ke namespace global menjadi ilegal, saya lebih suka menggunakan std::versi yang memenuhi syarat. (Ditambah saya agak berharap mereka membuatnya ilegal).
Galik
3
@ Galalik: Setuju. Itu akan mengamankan banyak pertanyaan bodoh tentang masalah C menggunakan kompiler C ++.
terlalu jujur ​​untuk situs ini
7
Tidak ada "sedikit hamil". C adalah bagian dari, atau bukan. Faktanya, tidak . Itulah alasan mengapa header C harus dimodifikasi agar berfungsi di C ++.
terlalu jujur ​​untuk situs ini
2
"Hampir semua" adalah ukuran yang sangat tidak berguna ketika berbicara tentang sekumpulan banyak elemen yang tak terhitung jumlahnya. Dengan argumen yang sama Anda mungkin bisa menghubungkan C dan Java.
Daniel Jour
9
@sasauke tidak, ini bukan bagian. C dan C ++ pasti berbagi subset, tetapi C itu sendiri bukan subset dari C ++.
The Paramagnetic Croissant

Jawaban:

106

Dari C ++ 11 Standard (penekanan saya):

Header perpustakaan standar D.5 C [depr.c.headers]

  1. Untuk kompatibilitas dengan pustaka standar C ...
  2. Setiap header C, yang masing-masing memiliki nama dalam format name.h , berperilaku seolah-olah setiap nama yang ditempatkan di namespace library standar dengan header cname yang sesuai ditempatkan dalam cakupan namespace global . Tidak ditentukan apakah nama-nama ini pertama kali dideklarasikan atau ditentukan dalam lingkup namespace (3.3.6) dari namespace std dan kemudian dimasukkan ke dalam cakupan namespace global dengan menggunakan deklarasi eksplisit (7.3.3).
  3. Contoh: Header <cstdlib> pasti memberikan deklarasi dan definisinya di dalam namespace std . Ini juga dapat memberikan nama-nama ini dalam namespace global. Header <stdlib.h> pasti memberikan deklarasi dan definisi yang sama dalam namespace global , seperti di C Standard. Ini juga dapat memberikan nama-nama ini dalam namespace std.

Menggunakan header «name.h» tidak digunakan lagi, header tersebut telah diidentifikasi sebagai kandidat untuk dihapus dari revisi mendatang.

Jadi, saya akan menyarankan untuk memasukkan header «cname» dan menggunakan deklarasi dan definisi dari stdnamespace.

Jika Anda harus menggunakan header «name.h» karena beberapa alasan (sudah usang, lihat di atas), saya akan menyarankan untuk menggunakan deklarasi dan definisi dari namespace global.

Dengan kata lain: lebih memilih

#include <cstdio>

int main() {
    std::printf("Hello world\n");
}

lebih

#include <stdio.h>

int main() {
    printf("Hello world\n");
}
sergej
sumber
1
N3242 bukanlah standar C ++. N3337 draf dengan perbedaan paling sedikit dari C ++ 11.
MM
3
Lihat juga Mengapa <cstdlib> Jonathan Wakely lebih rumit daripada yang mungkin Anda pikirkan dari blog Red hat. Dia merinci sejumlah masalah dari perspektif pelaksana pustaka standar C ++. Dia juga memberikan sejarah kembali ke C ++ 98.
jww
@sergej - Apakah Anda kebetulan mengetahui perlakuan C ++ 03 pada subjek? Atau terpukul atau luput apa yang akan terjadi?
jww
5
<name.h> mungkin sudah tidak digunakan lagi, tidak ada kemungkinan mereka akan dihapus dalam waktu dekat. Justru sebaliknya. Ada proposal untuk menghapus label yang tidak berlaku lagi, lihat open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . "Akhirnya, tampak jelas bahwa header C pada dasarnya akan dipertahankan selamanya, sebagai lapisan kompatibilitas yang penting dengan C dan POSIX. Mungkin ada gunanya membatalkan header, [..]"
Sjoerd
82

<cmeow>selalu menyediakan ::std::purrdan mungkin atau mungkin tidak menyediakan ::purr.

<meow.h>selalu menyediakan ::purrdan mungkin atau mungkin tidak menyediakan ::std::purr.

Gunakan formulir yang dijamin disediakan oleh tajuk yang Anda sertakan.

TC
sumber
7
STL dalam penyamaran yang buruk?
nwp
@nggak. (15 karakter)
TC
@TC Sayangnya, saat saya mencoba compiler saya, tidak ada <cmeow>atau <meow.h>tidak memberikan ::std::purratau ::purrmelainkan kesalahan pra-prosesor. Hanya <cstdio>dan / atau <stdio.h>menyediakan ::std::printfdan / atau ::printf. : P
LF
4
@ LF Anda mungkin perlu strcatmembuat ::purr.
Lundin
8

Tidak, kamu baik-baik saja.

The original intent adalah bahwa <___.h>header akan menjadi C versi yang meletakkan segala sesuatu dalam namespace global, dan <c___>header akan menjadi C ++ - versi ified, yang tempat segala sesuatu di stdnamespace.

Dalam praktiknya, versi C ++ juga memasukkan semuanya ke dalam namespace global. Dan tidak ada konsensus yang jelas bahwa menggunakan std::versi adalah "hal yang benar untuk dilakukan".

Jadi pada dasarnya, gunakan mana saja yang Anda suka. Yang paling umum mungkin adalah menggunakan fungsi pustaka standar C di namespace global ( printfbukan std::printf), tetapi tidak banyak alasan untuk menganggap satu "lebih baik" daripada yang lain.

jalf
sumber
2
"Dan tidak ada konsensus yang jelas bahwa menggunakan std :: versi adalah" hal yang benar untuk dilakukan "." Eh, ya sudah pasti ada konsensus bahwa itu adalah hal yang benar untuk dilakukan.
Miles Rout
4
Bagaimana seseorang secara obyektif menentukan apakah konsensus telah tercapai atau tidak?
Jeremy Friesner
9
@JeremyFriesner Anda memposting tentang hal itu di SO dan melihat apakah Anda mendapatkan komentar yang tidak setuju. :)
jalf
1
@JeremyFriesner: Standar tidak menjamin versi header C ++ menempatkan pengidentifikasi di namespace global. Standar ini juga tidak menggunakan versi header C. Itu terlihat cukup konsensus bagi saya. ;-)
DevSolar
2
@DevSolar mencari kata "konsensus" di kamus, lalu. Ini bukan tentang apa yang dikatakan standar, tetapi apa yang dikatakan programmer C ++ - dan terutama, apa yang mereka lakukan . Ada alasan mengapa setiap implementasi pustaka standar menyediakan header C, dan meminta header C ++ meletakkan semuanya di namespace global juga. :)
jalf
3

Satu-satunya perbedaan adalah std::printf()dengan menambahkan std::resolusi cakupan, Anda akan mengamankan diri Anda sendiri dari seseorang yang menulis fungsi dengan nama yang sama di masa mendatang, yang akan menyebabkan konflik namespace. Kedua penggunaan tersebut akan menghasilkan panggilan API OS yang sama persis (Anda dapat memeriksanya di Linux dengan menjalankannya strace your_program).

Saya merasa sangat tidak mungkin seseorang akan menamai fungsi seperti itu, seperti printf()salah satu fungsi yang paling umum digunakan di luar sana. Juga, di C ++, iostreams lebih diutamakan daripada panggilan ke cstdiofungsi seperti printf.

syntagma
sumber
1
Sebaliknya, saya merasa sangat mungkin: printfsangat rusak di C ++ karena kurangnya pengetikan yang kuat, menggantinya dengan versi yang lebih baik cukup alami.
Konrad Rudolph
1
@KonradRudol Anda dapat menemukannya jika Anda suka, tetapi Anda salah; ini tidak dimaksudkan untuk memiliki pengetikan yang kuat, dan ada banyak masalah yang tidak dapat diselesaikan dengan pengetikan yang kuat yang dibutuhkan dengan mudah. Itulah mengapa banyak solusi C ++ yang sebanding jauh lebih lambat daripada printf. Jika Anda ingin menggantinya dengan versi yang "lebih baik", Anda memutuskan kontrak antara bahasa dan pemrogram, dan pada awalnya berada dalam keadaan berdosa.
Alice
1
@Alice Uhm, saya tidak melanggar kontrak apa pun: std::printfberbeda dari mynamespace::printf, dan C ++ secara eksplisit mengizinkan saya untuk mendefinisikan fungsi saya sendiri yang namanya membayangi mereka dari fungsi di dalamnya std. Itu tidak bisa diperdebatkan. Adapun klaim Anda yang printfefisien karena mengetik longgar, itu tentu juga salah. printfbahkan tidak terlalu efisien, ada banyak implementasi yang lebih efisien yang sangat diketik.
Konrad Rudolph
@KonradRol Sepenuhnya salah; Anda melanggar kontrak, yang ditulis dalam standar, bahwa printf tanpa bilangan apapun berlaku secara jelas untuk konstruksi C. Penggunaan Anda atas namespace, alias ruang nama global, bukanlah ide yang baik. Itu tidak bisa diperdebatkan .
Alice
5
@Alice Bisakah Anda mengutip standar ini? Saya tidak mengetahui pembicaraan semacam itu.
Konrad Rudolph
3

Dari standar C ++ 11:

Setiap header C, yang masing-masing memiliki nama dalam format name.h, berperilaku seolah-olah setiap nama yang ditempatkan di namespace library standar dengan header cname yang sesuai ditempatkan dalam cakupan namespace global. Tidak ditentukan apakah nama-nama ini pertama kali dideklarasikan atau ditentukan dalam lingkup namespace (3.3.6) dari namespace std dan kemudian dimasukkan ke dalam cakupan namespace global dengan menggunakan deklarasi eksplisit (7.3.3).

Jadi, jika Anda menggunakan <cstdio>, Anda bisa yakin, itu printfakan ada di namespace std, dan karenanya tidak di namespace global.
Menggunakan namespace global menciptakan konflik nama. Ini bukan cara C ++.

Oleh karena itu, saya menggunakan <cstdio>header dan menyarankan Anda untuk melakukannya.

NeonMercury
sumber
4
Meskipun saya berharap ini berhasil, ini tidak benar. Jika Anda memasukkan <cstdio>Anda dijamin bahwa std :: printf akan ada, tetapi tidak ada jaminan dari standar if :: printf akan ada atau tidak juga. Bahkan, di setiap compiler yang pernah saya dengar dari :: printf adalah disuntikkan ke dalam namespace global bila Anda termasuk <cstdio>.
wjl
3

Dari praktik saya sendiri: gunakan std::prefiks. Jika tidak, suatu hari abs nanti menggigit Anda dengan sangat menyakitkan jika Anda menggunakan floating point.

Tidak memenuhi syarat absmengacu pada fungsi yang ditentukan intdi beberapa platform. Pada orang lain itu kelebihan beban. Namun std::absselalu kelebihan beban untuk semua tipe.

eiennohito
sumber
2

Menggunakan hanya printftanpa std::dapat menghasilkan beberapa konflik nama dan dianggap sebagai praktik yang buruk oleh banyak c ++ dev. Google adalah teman Anda yang satu ini, tetapi ini ada beberapa tautan, semoga ini membantu

Mengapa "menggunakan namespace std" dianggap praktik yang buruk? http://www.cplusplus.com/forum/beginner/61121/

razvan
sumber
4
using namespace stdadalah praktik yang buruk, tetapi menggunakan printftanpa std::kualifikasi tidak.
syntagma
using namespace std;bukan masalah saya di sini. Saya tidak pernah menggunakannya. printf();dan std::printf();bekerja di C ++ tanpa using namespace std;Itu sebabnya saya memposting pertanyaan.
DeiDei
@REACHUS Tidak setuju. Tidak ada perbedaan antara kedua skenario tersebut.
Konrad Rudolph
Saya tidak akan pernah menggunakannya std::printfkarena rasanya sangat aneh.
trenki
@KonradRudol Saya tidak mengatakan ada perbedaan, saya hanya menyatakan pendapat saya (lihat jawaban saya untuk alasan lebih lanjut).
syntagma
2

Di stdio

Ini adalah versi C ++ dari header C Library Standar @c stdio.h, dan isinya (sebagian besar) sama dengan header tersebut, tetapi semuanya terdapat dalam namespace @c std (kecuali untuk nama yang didefinisikan sebagai makro di C).

Jadi seharusnya tidak ada bedanya.

anukul
sumber