"Size_t" için hangi başlığı eklemeliyim?


100

Cppreference.com'a göre size_tbirkaç başlıkta tanımlanmıştır, yani

<cstddef>
<cstdio>
<cstring>
<ctime>

Ve C ++ 11'den beri,

<cstdlib>
<cwchar> 

Öncelikle neden böyle olduğunu merak ediyorum. Bu KURU prensibiyle çelişmiyor mu? Ancak sorum şu:

Kullanmak için yukarıdaki başlıklardan hangisini eklemeliyim size_t? Hiç önemli mi?


2
İlgili başlık dosyalarını açın ve tanımı bulun.
i486

35
@ i486 - Bu taşınabilir olmayan kırılgan kod yazmak için harika bir yoldur!
Sean

3
@Panagiotis C ++ standart kitaplığının bir parçası olan ve muhtemelen iddia edilen 'gerçek C ++' başlıklarınızın hiçbirinde çoğaltılmayan Kanavos C başlıkları. Tam olarak ne demek istiyorsun?
underscore_d

14
Hep kullanılan <cstddef>içinstd::size_t
Boiethios

4
@PanagiotisKanavos Elbette, bu genellikle iyi bir tavsiye, ancak bu durumda uygun görünmüyor - çünkü C ++ yerine std::size_tgeçmiyor ve OP, eski C işlevlerini kullanmayı savunmuyor, sadece typedef'i paylaşmaları hakkındaki alıntıyı gözlemleyerek. Bu konuyu okuyan birinin bu nedenle eski türleri / işlevleri kullanmaya yanıltılacağından şüpheliyim, ancak yapmadıklarından emin olmak istiyorsanız, o zaman yeterince adil!
underscore_d

Yanıtlar:


96

İçe aktardığım işlevleri ve türleri en aza indirmek istediğimi varsayarsak, cstddef herhangi bir işlev bildirmediği ve yalnızca 6 tür bildirdiği için . Diğerleri sizin için önemli olmayabilecek belirli alanlara (dizeler, zaman, IO) odaklanır.

Not cstddefsadece tanımlamak için garanti std::size_ttanımlayan olduğunu size_tad alanında stdo halde, olabilecek genel ad (etkin düz da bu ad size_t).

Bunun aksine, stddef.h(aynı zamanda C civarında uygun bir başlıktır) tanımlamak için garanti size_tgenel ad ve edebilir da sağlar std::size_t.


3
Herhangi bir garanti olduğunu var mı size_tgelen cstddefaynıdır ve her zaman diğerleriyle aynı olacak? Görünüşe göre ortak tanımlara sahip ortak bir başlık dosyası olmalı size_t...
SnakeDoc

1
@SnakeDoc ve sanki sihir yoluyla, buradaki başka bir cevap, bir 'dahili' başlık aracılığıyla tam olarak bunun gerçekleştiğini zaten gözlemledi.
underscore_d

5
@SnakeDoc Evet ve bu başlık cstddef.
user253751

2
@SnakeDoc, kendilerininkini tanımladığını kim söylüyor? Tüm standart, bu başlıkları ekledikten sonra tanımlanacağını söylüyor, hepsinin yeniden tanımlaması gerektiğini söylemiyor. Hepsi içerebilir <cstddef>veya hepsi sadece tanımlayan bazı dahili başlık içerebilir size_t.
Jonathan Wakely

1
csttddefcevap bir yazım hatası? Belki cstddefkastedilmektedir?
Erik Sjölund

47

Aslında, birkaç başlığın özeti (C ++ standardına dahil edilmiştir) size_t, türü özel olarak içerir ve ayrıca başka üstbilgiler de tanımlar size_t( <cX>başlıklar yalnızca ISO C <X.h>başlıkları olduğu için C standardına göre ,size_t not edilmiştir).

C ++ standart Ancak belirtmektedir <cstddef>tanımı içinstd::size_t

  • içinde 18.2 türleri ,
  • içinde sizeof 5.3.3 ,
  • içinde 3.7.4.2 Deallocation fonksiyonları (ki 18.2 belirtir) ve
  • içinde 3.7.4.1 ayırma işlevleri (aynı zamanda 18.2 belirtir).

Bu nedenle ve <cstddef>yalnızca türleri tanıttığı ve hiçbir işlevi olmadığı için, std::size_tkullanılabilir hale getirmek için bu başlığa bağlı kalırım .


Birkaç şeye dikkat edin:

  1. Türü, başlık eklemeden std::size_tkullanılarak elde edilebilirdecltype

    Yine de kodunuza bir typedef eklemeyi planlıyorsanız (yani bir kapsayıcı yazdığınız ve bir size_typetypedef sağlamak istediğiniz için ) sizeof, teose operatörleri başına döndüğünden, türünüzü hiçbir başlık eklemeden tanımlamak için global sizeof...veya alignofoperatörleri kullanabilirsiniz. std::size_tstandart tanım ve decltypebunlarda kullanabilirsiniz :

    using size_type = decltype(alignof(char));
    
  2. std::size_tstd::size_tbağımsız değişkenli işlevler olmasına rağmen küresel olarak görünür değildir .

    Örtük olarak bildirilen genel ayırma ve serbest bırakma işlevleri

    void* operator new(std::size_t);
    void* operator new[](std::size_t);
    void operator delete(void*);
    void operator delete[](void*);
    

    tanıtmak OLMAYAN size_t, stdya std::size_tve

    uygun başlık eklenerek isim beyan edilmedikçe, atıfta bulunulması stdveya biçimsiz olmasıstd::size_t

  3. std::size_tAynı ad alanında aynı türe atıfta bulunan birden çok typedef olması mümkün olsa da kullanıcı yeniden tanımlayamayabilir .

    Çoklu tanımların oluşumu rağmen size_tiçinde stdbaşına mükemmel geçerlidir 7.1.3 / 3'e , kadar hiçbir bildiri eklemek için izin verilmez namespace stdolarak başına 17.6.4.2.1 / 1 :

    Bir C ++ programının davranışı, aksi belirtilmedikçe, std ad alanına veya std ad alanı içindeki bir ad alanına bildirimler veya tanımlar eklerse tanımsızdır.

    İçin uygun bir typedef ekleme size_tad değil ihlal does 7.1.3 ama ihlal does 17.6.4.2.1 istenmeyen davranışlara ve potansiyel.

    Açıklama: 7.1.3'ü yanlış yorumlamamaya çalışın ve açıklamaları veya tanımları eklemeyin std(typedef'in bir şablon uzmanlığı olmadığı birkaç şablon uzmanlığı durumu dışında). Genişletmenamespace std


1
Yinelenen bir typedef'in yeni bir tür sunmadığı gerçeğini kaçırırsınız. Yalnızca tamamen geçerli olan yinelenen bir typedef ekler.
Maxim Egorushkin

@MaximEgorushkin: stdYinelenen typedef'ler yasadışı olduğundan yeniden tanımlayıcı typedef eklemenin geçersiz olduğunu iddia etmiyorum. Yasadışı olduğunu söylüyorum çünkü namespace stdyasal olup olmadıkları önemli değil, tanım eklemeyebilirsiniz .
Pixelchemist

Tüm bu standart alıntılardan bildiğimiz tek şey göz önüne alındığında, potansiyel olarak ne bozabilir?
Maxim Egorushkin

12
@MaximEgorushkin: Herhangi bir şey. Tanımlanmamış davranış bununla ilgili, değil mi? Bu nokta olabilir çalışmak veya bu baş noktası yoktur rasgele derleyici üzerinde kırılmaz standartlarına göre tanımlanan programın davranışını yapmaz. Ya da "fredoverflow" un burada güzelce ifade ettiği gibi : "C ++ standardı tek oy hakkına sahiptir, nokta."
Pixelchemist

Eleştirel düşüncenizi kullanmanızı istiyorum. Potansiyel olarak ne bozulabilir?
Maxim Egorushkin

9

Tüm standart kitaplık başlık dosyaları aynı tanıma sahiptir; kendi kodunuza hangisini eklediğiniz önemli değildir. Bilgisayarımda şu beyanı var _stddef.h. Bu dosya, listelediğiniz her dosyaya dahildir.

/*
   Define the size_t type in the std namespace if in C++ or globally if in C.
   If we're in C++, make the _SIZE_T macro expand to std::size_t
*/

#if !defined(_SIZE_T) && !defined(_SIZE_T_DEFINED)
#  define _SIZE_T_DEFINED
#if defined(_WIN64)
   typedef unsigned __int64 size_t;
#else
   typedef unsigned int size_t;
#endif
#  if defined(__cplusplus)
#    define _SIZE_T std::size_t
#  else
#    define _SIZE_T size_t
#  endif
#endif

2
emin değilim, ama derleme zamanı için önemli olduğunu düşünüyorum, değil mi?
most_prime_is_463035818

@ tobi303 bu özel soru için değil. Evet, gerekenden daha büyük bir başlık ekleyebilirsiniz, ancak daha sonra bir C ++ projesine zaten bir C başlığı eklediniz. Neden size_tilk etapta ihtiyacınız var ?
Panagiotis Kanavos

Tanımlamak için işletim sistemi makro koklamasını kullanmak iyi bir fikir değildir size_t. Daha portatif olarak tanımlayabilirsiniz using size_t = decltype( sizeof( 42 ) ). Ancak <stddef.h>neredeyse sıfır maliyeti olduğu için buna gerek yok .
Şerefe ve hth. - Alf

6

Başlıksız yapabilirsin:

using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); //  The shortest is my favourite.
using size_t = decltype(sizeof "anything");

Bunun nedeni, C ++ standardının şunları gerektirmesidir:

Sonuç sizeofve sizeof...sabit bir türdür std::size_t. [Not: std::size_tstandart başlıkta <cstddef>(18.2) tanımlanmıştır. - son not]

Başka bir deyişle, standart şunları gerektirir:

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");

Ayrıca , aynı typedef-name'in diğer tüm bildirimleriyle eşleştiği sürece, bu typedefbildirimi globalde ve stdad alanında yapmanın tamamen iyi olduğunu unutmayın.typedef (eşleşmeyen bildirimlerde bir derleyici hatası verilir).

Bunun nedeni ise:

  • §7.1.3.1 Bir typedef-name , bir sınıf bildirimi (9.1) veya enum bildiriminin yaptığı gibi yeni bir tür tanıtmaz .

  • §7.1.3.3 Belirli bir sınıf dışı kapsamda, bir typedeftanımlayıcı, o kapsamda beyan edilen herhangi bir türün adını, halihazırda atıfta bulunduğu türe atıfta bulunmak üzere yeniden tanımlamak için kullanılabilir.


Bunun ad alanına yeni bir türün eklenmesi anlamına geldiğini söyleyen şüpheciler için std ve böyle bir eylemin standart tarafından açıkça yasaklandığını ve bunun UB olduğunu ve her şeyin orada olduğunu için; Bu tutumun, altta yatan sorunların daha derinlemesine anlaşılmasını görmezden gelmek ve inkar etmek anlamına geldiğini söylemeliyim.

Standart, ad alanına yeni bildirimler ve tanımlar eklemeyi yasaklar stdçünkü bunu yaparak kullanıcı standart kitaplığı karıştırabilir ve tüm bacağını vurabilir. Standart yazarlar için, kullanıcının yapmaması gereken her şeyi yasaklamak ve önemli bir şeyi (ve o ayağı) gözden kaçırma riskini almak yerine, kullanıcının birkaç belirli şeyi uzmanlaştırmasına izin vermek ve iyi bir önlem için başka bir şey yapmayı yasaklamak daha kolaydı. Geçmişte, hiçbir standart konteynerin tamamlanmamış bir tiple somutlaştırılmamasını talep ederken yaptılar , oysa aslında bazı konteynerler bunu yapabilirdi ( bkz.Standart Kütüphaneci: Eksik Türlerin Konteynerleri, Matthew H. Austern ):

... Sonunda, her şey çok karanlık ve çok az anlaşılmış görünüyordu; standardizasyon komitesi, STL kaplarının eksik türlerle çalışmaması gerektiğini söylemek dışında bir seçenek olmadığını düşündü. İyi bir önlem için, bu yasağı standart kütüphanenin geri kalanına da uyguladık.

... Geriye dönüp bakıldığında, teknoloji daha iyi anlaşıldığına göre, bu karar hala temelde doğru görünüyor. Evet, bazı durumlarda, bazı standart kapsayıcıların tamamlanmamış türlerle somutlaştırılmaları için uygulanması mümkündür - ancak diğer durumlarda bunun zor veya imkansız olacağı da açıktır. Çoğunlukla, kullandığımız ilk testin std::vectorkolay durumlardan biri olması şans eseri idi .

Dil kurallarının std::size_ttam olarak olması gerektiği düşünüldüğünde decltype(sizeof(int)), yapmak namespace std { using size_t = decltype(sizeof(int)); }hiçbir şeyi bozmayan şeylerden biridir.

C ++ 11'den önce, çok sayıda şablon almadan sonuç decltypetürünü sizeoftek bir basit ifadede bildirmenin bir yolu yoktu ve bu nedenle de yoktu . size_tfarklı hedef mimarilerinde farklı türleri takma adlar, ancak, yalnızca sonucu için yeni bir yerleşik tür eklemek zarif bir çözüm olmaz sizeofve standart yerleşik yazım türleri yoktur. Bu nedenle, o zamanki en taşınabilir çözüm, size_tbelirli bir başlığa tür takma adı koymak ve bunu belgelemekti.

C ++ 11'de artık standardın bu tam gerekliliğini tek bir basit bildirim olarak yazmanın bir yolu var.


6
@Sean Yazdıkların hiçbir anlam ifade etmiyor.
Maxim Egorushkin

15
@MaximEgorushkin Yarısı bu kodu anlamadı ... mükemmel çalışıyor. Bununla birlikte, bu yolu sevmiyorum: imo, bir başlık eklemek ve standardın tanımlamasına izin vermek daha iyidir.
Boiethios

9
Beyler, en azından mükemmel bir şekilde doğru cevapları oylamaya başlamadan önce etkileyici dili öğrenin.
Frédéric Hamidi

11
Tom, "Aynı şeyi tanımlayan 6 standart kütüphane başlığı var! Bu delilik! Bunun bir ve yalnızca bir tanımına ihtiyacımız var size_t!" Dedi . Bir dakika sonra Mary şöyle dedi: "Aman Tanrım! size_tStandart kitaplık başlıkları arasında 7 tanım var ve Tom düzenliyor! Üçüncü taraf kitaplıklarında muhtemelen daha fazlası var!" xkcd.com/927

6
Bu olası bir tanım olsa da size_t, bu OP'nin gerçek sorusuna cevap vermiyor: Sanki FILEbildirildiği başlık için sormuştum ve kendi başlığımı yazmanızı öneriyorsunuz.
edmz
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.