C ++ 'da C başlıklarını kullanırken, std :: işlevlerinden mi yoksa global isim alanından mı kullanmalıyız?


113

C bir şekilde, tam olarak değil, C ++ 'nın bir alt kümesidir. Yani C ++ 'daki C işlevlerinin / başlıklarının çoğunu adı biraz değiştirerek ( stdio.hto cstdio, stdlib.hto cstdlib) kullanabiliriz.

Sorum aslında biraz anlamsal. C ++ kodunda (GCC derleyicisinin en yeni sürümünü kullanarak), arayabilirim printf("Hello world!");ve std::printf("Hello world!");tamamen aynı şekilde çalışır. Ve kullandığım referansta da olarak görünüyor std::printf("Hello world!");.

Sorum şu, std::printf();C ++ 'da kullanılması tercih edilir mi? Bir fark var mı?


17
Bir gün Ckütüphane sembollerinin küresel isim alanına boşaltılmasını zorunlu kılmaları durumunda, std::nitelikli sürümleri kullanmayı tercih ederim . (Ayrıca bunu yasadışı yapmalarını isterdim).
Galik

3
@Galik: Kabul edildi. Bu, C ++ derleyicisini kullanarak C sorunları hakkında birçok aptalca soruyu güvenli hale getirir.
bu site için çok dürüst

7
"Biraz hamile" diye bir şey yok. C ya bir alt kümedir ya da değildir. Gerçek şu ki, öyle değil . C başlıklarının C ++ ile çalışması için değiştirilmesi gerekmesinin nedeni budur.
bu site için çok dürüst

2
"hemen hemen hepsi", sayılamayan birçok unsurdan bahsederken oldukça yararsız bir ölçüdür. Aynı argümanla muhtemelen C ve Java'yı ilişkilendirebilirsiniz.
Daniel Jour

9
@sasauke hayır, bu bir alt küme değil. C ve C ++ kesinlikle bir alt kümeyi paylaşır , ancak C'nin kendisi bir C ++ alt kümesi değildir .
Paramagnetik Kruvasan

Yanıtlar:


106

C ++ 11 Standardından (vurgu benim):

D.5 C standart kitaplık başlıkları [depr.c.headers]

  1. C standart kitaplığıyla uyumluluk için ...
  2. Her biri name.h biçiminde bir ada sahip olan her C başlığı, standart kitaplık ad alanına karşılık gelen cname başlığıyla yerleştirilen her ad , genel ad alanı kapsamına yerleştirilmiş gibi davranır . Öyle bu isimler ilk ilan veya ad alanı kapsamında tanımlanan olmadığını belirtilmemiş (3.3.6) ait ad std ve sonra açık kullanılarak-beyanname (7.3.3) ile genel ad kapsamı içine enjekte edilir.
  3. Örnek: Başlık , tanımlarını ve tanımlarını <cstdlib> kesinlikle ad alanı içinde sağlar std . Ayrıca bu adları genel ad alanı içinde sağlayabilir. Başlık , C Standardında olduğu gibi , küresel ad alanı içinde <stdlib.h> kesinlikle aynı bildirimleri ve tanımları sağlar . Bu isimleri isim alanı içinde de sağlayabilir .std

«Name.h» üstbilgilerinin kullanılması kullanımdan kaldırıldı, bunlar gelecekteki revizyonlardan kaldırılmaya aday olarak belirlendi.

Bu yüzden, "cname" başlıklarını eklemeyi ve stdisim alanındaki tanımları ve bildirimleri kullanmayı öneririm .

Bazı nedenlerden dolayı «name.h» başlıklarını kullanmanız gerekiyorsa (kullanımdan kaldırılmıştır, yukarıya bakın), global ad alanındaki bildirimleri ve tanımları kullanmanızı öneririm.

Başka bir deyişle: tercih et

#include <cstdio>

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

bitmiş

#include <stdio.h>

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

1
N3242 herhangi bir C ++ standardı değildir. N3337, C ++ 11'den en az farklılığa sahip taslak.
MM

3
Ayrıca Jonathan Wakely'nin Neden <cstdlib> Red hat bloglarında düşündüğünüzden daha karmaşık olduğuna bakın . Bir C ++ standart kitaplık uygulayıcısının bakış açısından bir dizi sorunu ayrıntılarıyla anlatıyor. Ayrıca C ++ 98'e giden bir geçmiş sağlar.
jww

@sergej - Konuyla ilgili C ++ 03 tedavisini biliyor musunuz? Yoksa ne olacak vuruldu mu yoksa özledim mi?
jww

5
<name.h> kullanımdan kaldırılmış olabilir, yakın zamanda kaldırılma şansı yoktur. Aslında tam tersi. Kullanımdan kaldırılmış etiketin kaldırılmasına yönelik bir teklif var, bkz. Open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0619r0.html#3.5 . "Son olarak, C başlıklarının C ve POSIX ile hayati bir uyumluluk katmanı olarak esasen sonsuza kadar tutulacağı açık görünüyor. Başlıkların açıklanmasına değebilir, [..]"
Sjoerd

82

<cmeow>her zaman sağlar ::std::purrve sağlayabilir veya sağlamayabilir ::purr.

<meow.h>her zaman sağlar ::purrve sağlayabilir veya sağlamayabilir ::std::purr.

Eklediğiniz başlık tarafından sağlanması garanti edilen formu kullanın.


7
Kötü kılık değiştirmiş STL?
nwp

@nwp hayır. (15 karakter)
TC

@TC Maalesef, derleyicimi denediğim gibi, ne <cmeow>ne sağladı <meow.h>ne ::std::purrde ::purrön işlemci hatası. Yalnızca <cstdio>ve / veya <stdio.h>sağlar ::std::printfve / veya ::printf. : P
LF

4
@LF Sen gerekebilir strcatüretmek için ::purr.
Lundin

8

Hayır, her iki şekilde de iyisin.

Orijinal niyet olmasıydı <___.h>başlıkları genel ad şeyi koymak C versiyonları olurdu ve <c___>ified versiyonları, içinde yer herşey - başlıkları C ++ olacağını stdad.

Pratikte, C ++ sürümleri de her şeyi küresel ad alanına yerleştirir. Ve std::sürümleri kullanmanın "yapılacak doğru şey" olduğu konusunda net bir fikir birliği yok.

Yani temelde hangisini tercih ederseniz onu kullanın. En yaygın olanı muhtemelen C standart kütüphane işlevlerini global ad alanında ( printfyerine std::printf) kullanmaktır, ancak birini diğerinden "daha iyi" olarak düşünmek için fazla bir neden yoktur.


2
"Ve std :: sürümlerini kullanmanın" yapılacak doğru şey "olduğu konusunda net bir fikir birliği yok." Evet, yapılacak doğru şeyin bu olduğu konusunda kesinlikle fikir birliği var.
Miles Rout

4
Bir fikir birliğine varılıp ulaşılmadığını objektif olarak nasıl belirleriz?
Jeremy Friesner

9
@JeremyFriesner, SO'da bununla ilgili paylaşımda bulunuyorsunuz ve farklı görüşler alıp almadığınıza bakın. :)
jalf

1
@JeremyFriesner: Standart, C ++ başlık sürümlerinin tanımlayıcıları genel ad alanına koyacağını garanti etmez. Standart ayrıca C başlık sürümlerini kullanımdan kaldırır. Bu bana oldukça fikir birliği gibi görünüyor. ;-)
DevSolar

2
@DevSolar bir sözlükte "fikir birliği" kelimesine bakın, o zaman. Bu standardın ne söylediği değil, C ++ programcılarının ne söylediği ve özellikle ne yaptıklarıyla ilgili . Kelimenin tam anlamıyla her standart kitaplık uygulamasının C başlıklarını sağlamasının ve C ++ başlıklarının her şeyi küresel ad alanına da koymasının bir nedeni vardır . :)
jalf

3

Buradaki tek fark, kapsam çözünürlüğünü std::printf()ekleyerek std::, gelecekte aynı adı taşıyan bir işlev yazan birinden kendinizi korumanızdır, bu da ad alanı çatışmasına yol açar. Her iki kullanım da tam olarak aynı OS API çağrılarına yol açacaktır (bunu Linux altında çalıştırarak kontrol edebilirsiniz.strace your_program ).

printf()Orada en sık kullanılan işlevlerden biri olduğu gibi , birinin böyle bir işlevi adlandırmasını pek olası bulmuyorum . Ayrıca, C ++ 'da iostreams cstdioprintf gibi işlevlere yapılan çağrılarda tercih edilir .


1
Aksine, oldukça muhtemel buluyorum: printfC ++ 'da güçlü yazım eksikliğinden dolayı ciddi şekilde bozuk, daha iyi bir sürümle değiştirmek oldukça doğal.
Konrad Rudolph

1
@KonradRudolph İstersen bu şekilde bulabilirsin, ama yanılıyorsun; güçlü yazım anlamına gelmez ve gerekli güçlü yazımla kolayca çözülemeyen birçok sorun vardır. Bu nedenle birçok benzer C ++ çözümü printf'den çok daha yavaştır. Onu "daha iyi" bir sürümle değiştirmek istiyorsanız, dil ve programcı arasındaki sözleşmeyi bozuyorsunuz ve başlangıçta günah durumundasınız.
Alice

1
@Alice Uhm, herhangi bir sözleşmeyi bozmuyorum: std::printffarklıdır mynamespace::printfve C ++ açıkça isimleri içerideki fonksiyonlardan gölgeleyen kendi fonksiyonlarımı tanımlamama izin verir std. Bu tartışmaya açık değil. printfGevşek yazım nedeniyle verimli olan iddialarınıza gelince , bu da elbette yanlış. printfözellikle verimli bile değil, güçlü bir şekilde yazılmış birçok daha verimli uygulama var.
Konrad Rudolph

@KonradRudolph Kesinlikle yanlış; herhangi bir nicelik belirteci olmadan printf'in bir C yapısına belirgin bir şekilde uygulandığına dair standartta yazılı sözleşmeyi bozuyorsunuz. Küresel ad alanını takma ad alanı kullanmanız iyi bir fikir değildir. Bu tartışmaya açık değil .
Alice

5
@Alice, bu konudaki standardı açıklayabilir misiniz? Böyle bir laf kalabalığından haberdar değilim.
Konrad Rudolph

3

C ++ 11 standardından:

Her biri name.h biçiminde bir ada sahip olan her C başlığı, standart kitaplık ad alanına karşılık gelen cname başlığıyla yerleştirilen her ad, genel ad alanı kapsamına yerleştirilmiş gibi davranır. Bu adların ilk olarak std ad alanının ad alanı kapsamı (3.3.6) içinde bildirilip tanımlanmadığı ve daha sonra açık kullanım-bildirimleri (7.3.3) ile genel ad alanı kapsamına enjekte edilip edilmediği belirtilmemiştir.

Kullanmak Yani, <cstdio>, o, emin olabilir printfolacak namespace stdve dolayısıyla değil genel ad.
Global bir ad alanı kullanmak, ad çatışması yaratır.Bu C ++ yolu değildir.

Bu nedenle, <cstdio>başlıkları kullanıyorum ve bunu yapmanızı tavsiye ediyorum.


4
Bu şekilde çalışmasını istememe rağmen, bu doğru değil. Dahil ederseniz <cstdio>, std :: printf'in var olacağı garanti edilir, ancak standart if :: printf'in de var olup olmayacağına dair bir garanti yoktur . Aslında, şimdiye kadar duyduğum her derleyicide :: printf , dahil ettiğinizde global isim alanına enjekte edilir <cstdio>.
wjl

3

Kendi pratiğimden: std::ön ekleri kullanın . Aksi takdirde bir günabs olacak durumda çok acı seni ısırmak kayan noktalarını kullanarak.

Niteliksiz , bazı platformlarda abstanımlanan işlevi ifade eder int. Diğerlerinde aşırı yüklenmiştir. Ancak std::absher tür için her zaman aşırı yüklenir.


2

Sadece printfolmadan kullanmak std::bazı ad çatışmalarına neden olabilir ve birçok c ++ geliştiricisi tarafından kötü bir uygulama olarak kabul edilir. Google bu konuda arkadaşınız, ancak işte bazı bağlantılar, umarım bu yardımcı olur

"Std ad alanını kullanmak" neden kötü bir uygulama olarak kabul edilir? http://www.cplusplus.com/forum/beginner/61121/


4
using namespace stdkötü bir uygulamadır, ancak niteleyici printfolmadan kullanmak std::değildir.
syntagma

using namespace std;benim sorunum değil. Ben asla kullanmıyorum.printf();ve std::printf();C ++ ile çalışmadan using namespace std;bu yüzden soruyu gönderdim.
DeiDei

@ REACHUS Katılmıyorum. İki senaryo arasında hiçbir fark yok.
Konrad Rudolph

Asla kullanmam std::printf , sadece garip hissettiriyor.
trenki

@KonradRudolph Bir fark var demedim, sadece fikrimi ifade ettim (daha fazla mantık için cevabıma bakın).
syntagma

2

Standart olarak

Bu, Standart C Kitaplığı başlığı @c stdio.h'nin C ++ sürümüdür ve içeriği (çoğunlukla) bu başlık ile aynıdır, ancak tümü @c std ad alanında yer alır (içinde makro olarak tanımlanan adlar hariç) C).

Yani herhangi bir fark yaratmamalı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.