String :: Compare neden bir int döndürür?


102

Neden veya gibi daha küçük bir tür yerine bir string::comparedöndürür ? Anladığım kadarıyla bu yöntem yalnızca -1, 0 veya 1 döndürüyor.intshortchar

İkinci kısım, iki tür nesneyi karşılaştıran bir karşılaştırma yöntemi tasarlayacak Fooolsaydım ve yalnızca -1, 0 veya 1 döndürmek isteseydim, kullanmak mı shortyoksa chargenel olarak iyi bir fikir mi olurdu ?

DÜZENLEME: Düzeltildim, string::compare-1, 0 veya 1 döndürmüyor, aslında> 0, <0 veya 0 değerini döndürüyor. Beni sıraya koyduğunuz için teşekkürler.

Görünüşe göre cevap kabaca, daha küçük bir tür döndürmek için hiçbir neden yok intçünkü dönüş değerleri "rvalues" ve bu "rvalues" int türünden (4 bayt) daha küçük olmanın faydası yok. Ayrıca, birçok kişi, çoğu sistemin yazmaçlarının büyük olasılıkla intzaten boyutta olacağına dikkat çekti , çünkü bu yazmaçlar ister 1, 2 veya 4 bayt değeri verseniz doldurulacaklar, bir döndürmenin gerçek bir avantajı yoktur. daha küçük değer.

DÜZENLEME 2: Aslında, hizalama, maskeleme, vb. Gibi daha küçük veri türleri kullanılırken fazladan işlem yükü olabilir gibi görünüyor. Genel fikir birliği, daha küçük veri türlerinin, çok fazla veriyle çalışırken bellekten tasarruf etmek için mevcut olduğudur. bir dizinin durumu.

Bugün bir şey öğrendim, tekrar teşekkürler çocuklar!


Bence bunun için kullanılabilecek daha spesifik bir tür olsaydı daha iyi olurdu. Ada95 tarzında sadece -1, 0 ve 1 içeren bir tane.
Sachin Kainth

23
Bağlantınızın dokümantasyonu string::compare(), dönüş değerinin <0, 0 ve> 0 -not- -1, 0 ve 1 olduğunu açıkça belirtir.
Captain Obvlious

6
Kullanmanın shortveya charyerine kullanmanın avantajı ne olabilir int? Çoğu mimari, bir fonksiyonun dönüş değerini bir kayıtta saklayacak ve bir kayıt intdefterine a shortveya veya gibi uyacaktır char. Ve charsayısal türler için kullanmak her zaman kötü bir fikirdir, özellikle de imzalı değerlerin doğru bir şekilde işlendiğini garanti etmeniz gerektiğinde.
Cody Grey

7
Kaptan Obvlious, adınız ve yorumunuz ... Sadece paha biçilemez.
Cody Smith

2
İşaretsiz charolduğu platformlarda sıfırdan küçükse dönüş değerini kontrol eden kod başarısız olacağından kullanmak kötü bir fikir olur char.
milleniumbug

Yanıtlar:


113

İlk olarak, şartname, 0mutlaka -1veya olması gerekmeyen, daha küçük, eşit veya daha büyük bir değer döndürecektir 1. İkincisi, dönüş değerleri rdeğerlerdir ve integral yükseltmeye tabidir, bu nedenle daha küçük bir şey döndürmenin bir anlamı yoktur.

C ++ 'da (C'de olduğu gibi), her ifade ya bir değerdir ya da bir değerdir. Tarihsel olarak, terimler, r değerlerinin yalnızca sağda görünebildiği bir atamanın solunda ldeğerlerin göründüğü gerçeğini ifade eder. Bugün, sınıf dışı tipler için basit bir yaklaşım, bir ldeğerin bellekte bir adresi olduğu, bir r değerinin olmadığıdır. Bu nedenle, bir rvalue adresini alamazsınız ve cv niteleyicileri ("erişim" koşulu) geçerli değildir. C ++ terimleriyle, sınıf türüne sahip olmayan bir rvalue, bir nesne değil, saf bir değerdir. Bir işlevin dönüş değeri, başvuru türü olmadığı sürece bir r değeridir. (Bir sicile uyan sınıf dışı tipler, örneğin bellekte değil, neredeyse her zaman bir kayıtta iade edilecektir.)

Sınıf türleri için, sorunlar nedeniyle bu gerçeği, biraz daha karmaşıktır olabilir bir rvalue üzerinde üye işlevleri çağırmak. Bu, r değerlerinin aslında this işaretçi için adreslere sahip olması gerektiği anlamına gelir ve cv niteliği aşırı yük çözümlemesinde rol oynadığından, cv nitelikli olabilir. Son olarak, C ++ 11, rvalue referanslarını desteklemek için birkaç yeni ayrım sunar; bunlar da esas olarak sınıf türleri için geçerlidir.

İntegral yükseltme int, an'dan küçük integral türleri bir ifadede r değerleri olarak kullanıldığında çoğu bağlamda yükseltilecekleri gerçeğini ifade eder int. Dolayısıyla short a, b;, ifadede bir değişken tanımlanmış olsa bile a + b, her ikisi de ave toplama gerçekleşmeden önce byükseltilir int. Benzer şekilde, eğer yazarsam a < 0karşılaştırma yapılır, değeri abir int. Pratikte, bunun bir fark yarattığı çok az durum vardır, en azından tamsayı aritmetiğinin sarmalandığı 2'nin tamamlayıcı makinelerinde (yani bugün çok azı hariç hepsi - Unisys ana bilgisayarlarının geriye kalan tek istisna olduğunu düşünüyorum). Yine de, daha yaygın makinelerde bile:

short a = 1;
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( a + 0 ) << std::endl;

farklı sonuçlar vermelidir: ilki eşdeğerdir sizeof( short ), ikincisi sizeof( int )(integral terfi nedeniyle).

Bu iki konu resmi olarak ortogonaldir; r değerlerinin ve l değerlerinin integral ilerlemeyle ilgisi yoktur. Bunun dışında ... integral yükseltme yalnızca rdeğerleri için geçerlidir ve bir rvalue kullanacağınız durumların çoğu (ancak hepsi değil) integral yükseltmeyle sonuçlanır. Bu nedenle, bundan daha küçük bir şeyde sayısal bir değer döndürmek için gerçekten bir neden yoktur int. Karakter türü olarak döndürmemek için çok iyi bir neden var. Aşırı yüklenmiş operatörler, örneğin <<, karakter türleri için genellikle farklı davranır, bu nedenle karakterleri yalnızca karakter türleri olarak döndürmek istersiniz. (Farkı şu şekilde karşılaştırabilirsiniz:

char f() { return 'a'; }
std::cout << f() << std::endl;      //  displays "a"
std::cout << f() + 0 << std::endl;  //  displays "97" on my machine

Aradaki fark, ikinci durumda, eklemenin, farklı bir aşırı yüklemenin <<seçilmesine yol açacak şekilde, integral yükselmenin meydana gelmesine neden olmasıdır .


46
return values are rvalues, subject to integral promotionCevabınızda daha fazlasını açıklarsanız iyi olur.
Alvin Wong

"dönüş değerleri doğru değerlerdir ... bu nedenle daha küçük bir şey döndürmenin bir anlamı yoktur" GİBİ
masoud

1
@AlvinWong: C karakterleri neden karakterler yerine değişmezler? Sorusunun yanıtlarını görün. daha fazla arka plan bilgisi için.
Jesse Good

Düzenlemenizin eklediği mükemmel açıklamadan sonra bunu tekrar + 1'leyebilmeyi dilerdim.
Cody Grey

Ya öyleyse signed char? İmzalı gibi mi davranır charyoksa farklı bir tip mi olur?
user541686

41

-1, 0 veya 1 döndürmemesi kasıtlıdır.

İzin verir (bunun dizeler için olmadığını, dizeler için de aynı şekilde geçerli olduğunu unutmayın)

int compare(int *a, int *b)
{
   return *a - *b;
}

şundan çok daha az kullanışlıdır:

int compare(int *a, int *b)
{
   if (*a == *b) return 0;
   if (*a > *b) return 1;
   return -1;
}

-1, 0 veya 1 döndürmek zorunda kalırsanız, yapmanız gereken şey budur [veya bu satırlar boyunca bir şey].

Ve daha karmaşık türler için de işe yarar:

class Date
{
    int year;
    int month;
    int day;
}

int compare(const Date &a, const Date &b)
{
   if (a.year != b.year) return a.year - b.year;
   if (a.month != b.month) return a.month - b.month;
   return a.day - b.day;
}

String durumunda, bunu yapabiliriz:

int compare(const std::string& a, const std::string& b)
{
   int len = min(a.length(), b.length());

   for(int i = 0; i < len; i++)
   {
      if (a[i] != b[i]) return a[i] - b[i];
   }
   // We only get here if the string is equal all the way to one of them
   // ends. If the length isn't equal, "longest" wins. 
   return a.length() - b.length();
}

8
İlk compareişleviniz, (neyse ki) alırsa char*ve ondan chardaha küçükse eşit olarak uygulanmayan taşma sorunlarına sahiptir int. Örneğin, eğer *aolduğunu MAX_INTve *bbir -1o *a - *bUB, ancak uygulama seçer neredeyse kesin sonra sonuç davranışını tanımlamak için ise negatiftir.
Steve Jessop

1
Son örnekle Sorun: length()döner bir size_t, daha büyük olabilir int...
F'x

Evet, dizeleriniz 2 GB'tan uzunsa bu bir sorun olabilir. Bir kez bir fifo'da bir şeyleri saklamak için bir test durumu olarak 1GB uzun dizeler yaptım. Ama elbette, Base64 olarak kodlanmış bir MPEG içeren bir dizeyle uğraşan biri ya da benzeri bir sorunla karşılaşabilir ...
Mats Petersson

@MatsPetersson bu daha çok temel bir problem çünkü soru "neden int
F'x

Pekala, bunun histerik olduğuna eminim - yani tarihsel nedenlerden bahsediyorum - ve muhtemelen strcmp / memcmp ve diğer karşılaştırma türü işlemlerle uyumlu olması için.
Mats Petersson

25

int genellikle (çoğu modern donanımda bu anlama gelir) sistem veriyolu ve / veya cpu yazmaçları ile aynı boyutta bir tam sayıdır, buna makine sözcüğü denir. Bu nedenle int genellikle daha küçük türlerden daha hızlı aktarılır çünkü hizalama, maskeleme ve diğer işlemler gerektirmez.

Daha küçük türler, esas olarak diziler ve yapılar için RAM kullanım optimizasyonuna izin vermek için mevcuttur. Çoğu durumda, daha iyi bir RAM kullanımı için birkaç CPU döngüsünü (aligment işlemleri şeklinde) takas ederler.

Dönüş değerinizi işaretli veya işaretsiz bir centain boyutu (char, short…) olarak zorlamanız gerekmedikçe, int kullanmak daha iyidir, bu yüzden standart kitaplık bunu yapar.


Şeylerin donanım tarafını mantıklı bir şekilde açıklamanın harika bir yolu.
Ogre Mezmuru33

10

Bu bir C-izm.

C- comparetürü işlevler gerektiğinde , her zaman bir int. C ++ bunu ileriye taşıdı (maalesef).

Ancak, intgenellikle kullanılan sistem kayıtlarının boyutu olduğundan , bir döndürme gerçekçi olarak muhtemelen en hızlı yoldur. (Kasıtlı olarak belirsiz.)


1
Gerçekte shortve charperformans cezaları uygulayabilir, örneğin 255+7a charve bir için farklı bir değere sahiptir , intbu nedenle doğru bir uygulama , anlamını teslim etmeye özen göstermeden bir charyere intgidebileceğini zorunlu olarak saklayamaz . Derleyiciler, bunun getirdiği verimsizliği mutlaka optimize etmeyecektir.
Jack Aidley

10

Yöntem aslında kümede bir tamsayı döndürmez { -1, 0, 1 }; aslında herhangi bir integral değer olabilir.

Neden? Düşünebildiğim ana sebep int, mimarinin "doğal boyut" değeri olması; bu boyuttaki değerler üzerindeki işlemler tipik olarak en az daha küçük veya daha büyük değerler üzerindeki işlemlerden daha hızlıdır (ve çoğu durumda daha hızlıdır). Yani bu, uygulamanın en hızlı olanı kullanması için yeterli bolluğa izin verme durumudur.


4

Foo türündeki iki nesneyi karşılaştıran bir karşılaştırma yöntemi tasarlayacak olsaydım ve yalnızca -1, 0 veya 1 döndürmek istersem, short veya char kullanmak genellikle iyi bir fikir olur mu?

Tamam fikir olurdu. Daha iyi bir yol, bir bool (yalnızca eşitse karşılaştırmak istiyorsanız) veya enum (daha fazla bilgi için) döndürmektir:

enum class MyResult
{
  EQUAL,
  LESS,
  GREATER
};

MyResult AreEqual( const Foo &foo1, const Foo & foo2 )
{
  // calculate and return result
}

3
"İyi olurdu". Bunun için bir gerekçeniz var mı?
jrok

4

Bazı kişilerin bir kodu C'den C ++ 'ya değiştirdiğini varsayalım. Onlar değiştirmeye karar verdi strcmpiçin string::compare.

Yana strcmpgetiri int, bu daha kolay string::comparedönmek inthediye olarak.


2

Muhtemelen daha çok strcmpbu dönüş değerleri kümesine sahip olduğu gibi çalışmasını sağlamak için . Kodu taşımak istiyorsanız, mümkün olduğunca yakın parçalanan değiştirmelere sahip olmak muhtemelen daha sezgisel olacaktır.

Ayrıca, dönüş değeri sadece değil -1, 0ya 1ama <0, 0ya >0.

Ayrıca, belirtildiği gibi, geri dönüş tamamlayıcı bir promosyona tabi olduğundan küçültmek mantıklı değildir.


-1

çünkü bir boole dönüş değeri yalnızca iki olası değer olabilir (doğru, yanlış) ve bir karşılaştırma işlevi üç olası değer (küçüktür, eşittir, büyüktür) döndürebilir.

Güncelleme

İşaretli bir kısa döndürmek kesinlikle mümkün olsa da , kendi karşılaştırma işlevinizi gerçekten uygulamak istiyorsanız, iki boole ile bir yarım bayt veya yapı değeri döndürebilirsiniz.


7
Sorunun hiçbir yerinde Boolean türünü döndürmekle ilgili bir şey söylemiyor. Aslında, özel olarak öneriyor shortve charalternatif olarak int.
Cody Grey
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.