SORU
22 Temmuz 2012, Pazar


Std::bu gerçekten güvenli mi?

std::stoi nedir? hakkında birisi ile hoş bir sohbet yaptım. Açıkça söylemek gerekirse, std::strtol DAHİLİ olarak kullanır, ve eğer bir hata bildirirse atar. Onlara göre, std::strtol "abcxyz", stoi yol girişi için bir hata std::invalid_argument atmak için rapor gerekmiyor ama.

Her şeyden önce, burada iki program bu gibi durumlarda davranışları hakkında GCC üzerinde test edilmiştir:
strtol
stoi

İkisi de "123" "abc" başarısızlık başarı göstermektedir.


Standart daha fazla bilgi çekmek için baktım:

§ 21.5

Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that  
no conversion could be performed. Throws out_of_range if the converted value is  
outside the range of representable values for the return type.

strtol güvenerek davranışları özetliyor. Şimdi ne strtol hakkında? C11 taslak olarak bunu buldum:

§7.22.1.4

If the subject sequence is empty or does not have the expected form, no  
conversion is performed; the value of nptr is stored in the object  
pointed to by endptr, provided that endptr is not a null pointer.

Verilen duruma geçerken "abc" C standart dikte nptr, hangi puan başına dize, depolanmak endptr işaretçi geçti. Bu test ile tutarlı görünüyor. Bu da belirttiği gibi, 0 iade edilmelidir,:

§7.22.1.4

If no conversion could be performed, zero is returned.

Önceki referans no dönüşüm geri 0 olmalı yani yapılan olacağını söyledi. Bu koşullar şimdi stoi C 11 standart std::invalid_argument atma ile uyumlu.


Sonuç bu bana göre önemli çünkü ben gitmek istemiyorum civarında tavsiye stoi olarak daha iyi bir alternatif diğer yöntemlerin string int dönüşümü, ya da kullanarak kendim gibi işler böyle yürüyordu bir şey kalmamış, değil mi yakalamak metin olarak geçersiz bir dönüşüm.

Tüm bunlardan sonra, bir yerde hata yaptım? Bu durum iyi bir kanıtı atılan var gibi geliyor bana. Benim kanıt geçerlidir, ya std::stoi "abc" verildiğinde bu özel durum için garanti değil mi?

CEVAP
22 Temmuz 2012, Pazar


std::stoi giriş hatası "abcxyz" atmak mı?

Evet.

Şaşkınlığınızı strtol asla raporlar gerçeğinden gelebilir bencebir hatataşma dışında. Hayır dönüşüm yapıldı rapor olabilir, ama bu hiçbir zaman C standart bir hata durumu olarak adlandırılır.

strtol tanımlanan benzer şekilde her üç C standartları, bana inanın sıkıcı ayrıntılar, ama temelde tanımlayan bir "konu dizisi" öyle bir dize giriş dizesi karşılık gelen gerçek sayı. Aşağıdaki dört koşullar eşdeğer

  • konu sıra beklendiği şeklinde bir sayı) (Türkçesi: vardır
  • konu sıra dışı boş
  • bir dönüşüm oluştu
  • *endptr != nptr / * endptr non-null olduğunda mantıklı)

Taşma olduğunda, dönüşüm hala meydana gelmiş olduğu söylenir.

Şimdi, "abcxyz" sayı içermiyor çünkü, dize "abcxyz" konu sırası dönüştürme yapılabilir böylece boş olması gerektiği oldukça açıktır. C90/C99/C11 aşağıdaki program deneysel olarak teyit edecektir

#include <stdio.h>
#include <stdlib.h>

int main() {
    char *nptr = "abcxyz", *endptr[1];
    strtol(nptr, endptr, 0);
    if (*endptr == nptr)
        printf("No conversion could be performed.\n");
    return 0;
}

Bu std::stoi herhangi bir uyumlu uygulama anlamına gelirgerekirgiriş verildiğinde invalid_argument isteğe bağlı temel bir argüman olmadan "abcxyz" atmak.


Bu std::stoi tatmin edici hata kontrolü olduğu anlamına mı geliyor?

Hayır. Kişi sendin konuşmak için doğru zaman diyor ki std::stoi daha yumuşak daha sahne tam kontrol errno == 0 && end != start && *end=='\0' sonra std::strtol çünkü std::stoi sessizce şeritler uzakta tüm karakterler başlayarak ilk sayısal olmayan karakter dizesi.

Aslında üstünü kafamda tek dil olan yerel dönüşüm davranır gibi biraz std::stoi Javascript, ve o zaman bile seni kuvvetleri üssü 10 parseInt(n, 10) önlemek için özel bir durum onaltılık sayılar:

input      |  std::atoi       std::stoi      Javascript      full check 
=========== =============================================================
hello      |  0               error          error(NaN)      error      
0xygen     |  0               0              error(NaN)      error      
0x42       |  0               0              66              error      
42x0       |  42              42             42              error      
42         |  42              42             42              42         
----------- -------------------------------------------------------------
languages  |  Perl, Ruby,     Javascript     Javascript      C#, Java,  
           |  PHP, C...       (base 10)                      Python...  

Not: boşluk ve gereksiz işaretler idare diller arasında farklılıklar vardır.


Tamam, tam hata denetimi istiyorum, ben ne yapmalıyım?

Herhangi bir yerleşik bu işlev farkında değilim ama boost::lexical_cast<int> ne istiyorsun. Hatta çevresindeki boşluk reddeder beri özellikle katı, int() fonksiyon Python benzemez. Geçersiz karakter ve taşmaları, boost::bad_lexical_cast aynı durum neden unutmayın.

#include <boost/lexical_cast.hpp>

int main() {
    std::string s = "42";
    try {
        int n = boost::lexical_cast<int>(s);
        std::cout << "n = " << n << std::endl;
    } catch (boost::bad_lexical_cast) {
        std::cout << "conversion failed" << std::endl;
    }
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • ETrade Supply

    ETrade Suppl

    23 Temmuz 2011
  • Matt Stokes

    Matt Stokes

    22 Ocak 2008
  • Sams Page :D

    Sams Page :D

    15 Mart 2009