Soru Neden 'auto', tekli eksi operatörüne uymuyor?


Ben C ++ için oldukça yeni ama bu davranışını buluyorum auto tuhaf:

class A{};

int main() {
    A a;
    auto x = -(sizeof(a));
    cout << x << endl;
    return 0;
}

Değişken x unsigned Bu durumda, değişkenin başlangıcında tekli eksi operatörü kullanmış olmama rağmen. Nasıl oldu sadece dönüş tipi sizeof (std::size_t) dikkate alınan operatör nedeniyle saklanan sayının negatif olacağı düşünülmüyor mu?

farkındayım size_t imzasız bir int.

Bunu GCC 8.1.0 ve C ++ 17 ile denedim.


32
2017-07-25 08:14


Menşei


Neden farklı bir şey beklerdin? Aynı şey yaptığınızda olur cout << -(sizeof(a)) << endl;. Bu otomatik ile sıfır yapacak. - PeterT
C tasarımcıları istediği için -imzasız değerler üzerinde geçerli olmak. Şahsen onu geçersiz kılardım. - Johannes Schaub - litb
Bu yanlış anlaşılma olabilir. auto C ++ diline yeni bir şey eklemez, şablon argüman türü indirimi için zaten mevcut olan aynı mekanizmayı kullanır. - PeterT
tekli eksi hariç herşeyi Diyerek 0u - x, aynı etkiyi alabilirsiniz -x. Belki de operatör ifadelerinde imzayı / imzasızlığı karıştırmayı bile yasaklıyorum. IMO hala izin vermek yararlı olabilir -1u.. bu yüzden imzasız üzerinde tekil olmayan eklerin yalnızca imzasız harflere izin verilebileceğini, ki bu da operatör ifadelerinde imzanın yasaklanmasını yasaklamaya benzer bir kural ekleyebilirim. - Johannes Schaub - litb
@curiousguy evet çünkü sarma-etrafında sadece çıkarma için özel bir durum. Sadece eğer sağ> soldan ise, etrafını sardınız. Diğer yandan olumsuzlama için, sadece etrafı sarmak, çoğu durumda 0 istisna olmak. - Johannes Schaub - litb


Cevaplar:


Buradaki asıl mesele, tek başına çalışan aritmetik işlemcilerin geri kalanında olduğu gibi, tek başına eksi operatörün kullanılmasıdır. İntegral promosyonlar. Şaşırtıcı bir şekilde, unary eksi uygulamasının sonucu size_t hala olacak size_t ve suçlamaya gerek yok auto.

Karşı örnek. Bu durumda, tümleşik promosyonlar türü nedeniyle x olacak int böylece çıkış olacak -1:

unsigned short a{1};
auto x{-a};
cout << x << endl;

28
2017-07-25 08:25



@ acraig5075 Hayır, şaşırtıcı bir şekilde demek istiyorum. İlk etapta imzasız türlere neden tekil eksi uygulanmasına izin verilmesi oldukça kafa karıştırıcıdır. Tekil eksi değerin işaretini değiştirmesi gerekiyordu, ama imzasız değerler işaretin değiştirilemez. - VTT
VTT ikili eksi, imzasız değerlere uygulanabilir, bu nedenle neden eksi olmamalıdır? - Caleth
İntegral promosyonun bununla ne ilgisi var? Görebildiğim kadarıyla burada hiçbir şey tanıtılmıyor; size_t içinde, size_t dışarı...?!? - DevSolar
@VTT İmzasız bir tamsayı pozitif bir tamsayı veya bir tam sayı modulo 2 ^ n olarak düşünebilirsiniz. İmzasız bir imzanın yokluğu sadece modülo aritmetik (Z / (2 ^ n) Z) terimi anlamında mantıklıdır. Ama bir dizi baytın bir tamsayı modülo olduğunu söylemek saçmalıktır, bu pozitif bir sayıdır. - curiousguy
@curiousguy: Temel sorun, imzasız türlerin iki ayrık amaçla kullanılmasıdır: modüler aritmetik işlemek veya üst sınırı ikiden az bir faktörle karşılık gelen imzalı türden daha yüksek doğal sayıları tutmak. Ne yazık ki, programcıların gerekli olanı belirtmesine izin vermekten ziyade, C basitçe "küçük" işaretsiz türlerin ikincisinin "tam boyutlu" olanlara sahip olması gerektiğini varsayar. - supercat


İfaden -(sizeof(a)) tekli uygular - operatör imzasız türden bir değere. Tek operatör - imzasız bir integral değeri imzalı birine dönüştürmez; bunun yerine hangi işaretsiz değerin böyle bir işlemin sonucu olacağını tanımlar (çapraz başvuru). cppreference.com'daki tekil aritmetik operatörler):

Yerleşik tekli eksi operatörü, negatifini hesaplar.   tanıtılan işlenen. İmzasız a için, -a değeri 2 ^ b'dir.   -a, burada promosyondan sonra bit sayısıdır.

Bu nedenle, şaşırtıcı olsa bile, auto tekdüze uygulama sonucu doğru çalışır - operatör imzasız bir değere hala imzasız bir değerdir.


21
2017-07-25 08:34



"operatör imzasız bir ayrılmaz değeri imzalı birine dönüştürmez"İmzasız modulo aritmetiği için kullanırsanız ve doğal sayılar için imzasız olarak kullanırsanız hiçbir şey ifade etmezseniz, bu tamamen duyulara neden olur." - curiousguy
Bundan bahsetmek isteyebilirsiniz size_t tüm ayrılmaz tipler gibi ayrılmaz bir promosyona tabidir, bu yüzden daha küçüktür int, terfi edecek int unustan önce eksi alır. Ama böyle sapık bir uygulama bilmiyorum. - Deduplicator


Sonucu (tekli) - imzasız bir değere uygulandığında imzasız ve sizeof işaretsiz bir değer döndürür.

Tek operatörün işletmecisi aritmetik veya unscoped olacaktır.   numaralandırma türü ve sonuç, işleneninin olumsuzlanmasıdır.   İntegral promosyon, integral veya numaralandırma işlenenleri üzerinde gerçekleştirilir.   İmzasız bir miktarın olumsuzluğu,   2 n'den n değeri, burada n, terfi edilen işlenendeki bitlerin sayısıdır.   Sonucun türü, tanıtılan işlenenin türüdür.

[expr.unary.op]

Sonucu sizeof ve sizeof... bir tür sabitidir    std​::​size_­t

[expr.sizeof]

Uygulama tanımlı davranışı önlemek için, int uygulamadan önce -

Hedef türü imzalanmışsa, değer değiştirilemez.   hedef türünde temsil edilen; aksi halde değer   Uygulama tanımlı.

[conv.integral]

class A{};

int main() {
    A a;
    auto x = -(int{sizeof(a)});
    cout << x << endl;
    return 0;
}

4
2017-07-25 08:31



Gösterdiğiniz için teşekkürler auto x = 0-(sizeof(a)); yol. - CodeShark
Eğer size_t daha büyük bir menzile sahip int (hemen hemen her zaman), sonra verilen size_t x,y=...;, sonra x=-y; ayarlayacak x mümkün olana size_t yapacağı değer x+y 0 verim. - supercat


Bir bakarsak: https://en.cppreference.com/w/cpp/language/sizeof, sonuç türü size_t hangisi unsigned. Açıklığın bunu bir signed int negatif değerlere izin vermek için

Yerine auto Yazabilirsin int hangi negatif değerlere izin verir.


1
2017-07-25 08:19



Yani açık bir şekilde söylüyorum ki bunu bir signed int? mı auto Her zaman sadece mantıklı olup olmadığını kontrol etmeden dönüş türünü kullanarak? Eğer öyleyse, burada döküm ile ilgili bir sorun görüyorum. - CodeShark
Tam olarak beyan etmelisin c++ negatif bir değer depolayacaksınız. auto değer bu yana bilmiyor çünkü size_t. Döküm, anlattığın için sana bir sorun vermeyecek c++ o bir olacak signed int. - Giovanni Terlingen
@CodeShark Burada "anlam ifade etmiyor" nedir? - curiousguy