2013-03-27 47 views
11

Bir C uygulamasında (ör., Bir x86 C derleyicide) USHRT_MAX = 65535 ve INT_MAX = 2147483647 varsayalım. Öyleyse, aşağıdaki ifade iyi tanımlanmış mı? bir taşma meydana çünkü bu yüzden, (intunsigned short bütün olası değerleri temsil edebilir çünkü) her iki işlenen int yükseltilirler C99 standart aşağıdaki göre veint promosyon: Aşağıdakiler iyi tanımlanmış mı?

unsigned short product = USHRT_MAX * USHRT_MAX; 

, sonuç, iyi tanımlanmamıştır (

6.3.1.1-1

int ca ise: 65535^2 = 4294836225 > 2147483647), product değeri iyi tanımlanmış olmadığı anlamına gelir ki n orijinal türdeki tüm değerleri temsil eder; değer, int'ye dönüştürülen ; aksi halde, imzasız bir int'ye dönüştürülür. Bunlar tamsayı promosyonları olarak adlandırılır. (48) Diğer tüm türler tamsayı promosyonları tarafından değiştirilmeyen vardır.

48) tam sayı promosyonlar sadece uygulanır:, tekli + ve işlenen için bir argüman ifadeler, her zamanki aritmetik dönüşüm parçası olarak -, ve • operatörler ve kaydırma iki işlenen için kendi alt bölümleri tarafından belirtildiği gibi operatörler. Negatif olmayan bir

6.2.5-9

aralığı: işaretsiz işlenen içeren hesaplamaları taşma yok çünkü

Bununla birlikte, aşağıdaki değerlere göre, sonuç, iyi tanımlı İmzalı bir tamsayı türünün değerleri, karşılık gelen imzasız tamsayı türünün bir alt kümedir ve gösteriminin her bir değerin aynı değeridir. (31) içeren bir hesaplamaişaretsiz işlenenler hiçbir zaman taşmayabilir, sonuçta elde edilen işaretsiz tamsayı türüyle temsil edilemeyen bir sonuç olmadığından, sonuç türü tarafından temsil edilen olabilen en büyük değerden büyük olan modulo .

yukarıda belirtilen açıklamada değişken product iyi tanımlanmış bir değere sahip mi?

EDIT: Aşağıdaki durumda ne olması gerekir?

unsigned short lhs = USHRT_MAX; 
unsigned short rhs = USHRT_MAX; 
unsigned short product = lhs * rhs; 
+2

Ahlaki: aritmetik için "int" den daha küçük türleri kullanmayın, kurallar, fani programcıların doğru kodu yazmasına izin vermek için çok kafa karıştırıcıdır ... –

+0

İki kod parçası arasında fark yoktur. Sabit ya da değişken kullanıp kullanmadığınızdan bağımsız olarak, 'int' için yapılan promosyonlar gerçekleşecektir. –

+2

Sadece bir nitpick gibi, ilk durumda 'int' için * promosyon * yoktur. "USHRT_MAX" ifadesi verilen * bir * int'dir. '65535U' olarak bildirilecekse, resmin tamamı değişecektir. –

cevap

4

Promosyon kazanır.

Aşağıda verilen değerlerin #if önişlemci kullanım için uygun olan sabit değerler ile değiştirilir sabitleri ile ilgili bölüme 5.2.4.2.1 USHRT_MAX vb .:

edenler. Ayrıca, CHAR_BIT ve MB_LEN_MAX haricinde, aşağıdaki , tam sayılı promosyonlara göre dönüştürülen karşılık gelen türde bir nesne olan bir ifadeyle aynı türde olan ifadeler ile değiştirilmelidir.

Yani çarpma int s üzerindedir ve hiçbir imzasız işlenen içerir, açık bir şekilde, USHRT_MAX < INT_MAX eğer imzasız işlenen içeren bir operasyon almak için USHRT_MAX uygulamak için hiçbir uyan bir yolu yoktur. Böylece taşma ve tanımlanmamış davranışınız var. katma soru

DÜZENLEME İlişkin

: Ne şu durumda olması gerekir? tam olarak aynı durumdur

unsigned short lhs = USHRT_MAX; 
unsigned short rhs = USHRT_MAX; 
unsigned short product = lhs * rhs; 

. * arasında işlenen tip unsigned short tüm değerleri çarpma int s üzerinde olacak şekilde, USHRT_MAX ve INT_MAX değerlerine varsayımı ile int s olarak temsil edilir ve belirtilen değerlerle taşmaları edilebilir, tam sayı promosyonlar tabidir.

Çoğaltmanın imzasız işlenenler üzerinde gerçekleştirilmesini sağlamak için, en az bir işleneni işaretsiz olarak int'a yükseltilmemiş işaretsiz bir türe dönüştürmeniz gerekir.

1

Sen çarpma operatörü uygulandığı zaman beri UB olsun, onun işlenenler ise (ilk çıkan int nedeniyle promosyonların) tamsayılar imzalanır.

çalışması-etrafında ki bununla: (unsigned)some_integer imzasız kalır

unsigned short product = USHRT_MAX * (unsigned)USHRT_MAX; 

kanıtı olduğunu:

#include <stdio.h> 

int main(void) 
{ 
    printf("1u * (-1) = %f\n", (((unsigned)1) * (-1)) + 0.0); 
    printf("1 * (-1) = %f\n", (1 * (-1)) + 0.0); 
    return 0; 
} 

Çıkış (ideone):

1u * (-1) = 4294967295.000000 
1 * (-1) = -1.000000 

İyi yakalamak btw.

+0

Bu işe yaramaz. Her zamanki aritmetik dönüşümlere göre: "Aksi takdirde, imzalanmış tamsayı türüne sahip işlenenin türü, işaretsiz tamsayı türüyle işlenenin türündeki tüm değerleri temsil ederse, o zaman işaretsiz tamsayı türüne sahip işlenenin türüne dönüştürülür. İmzalı tamsayı türü ile işlenen. " Böylece her iki işleneni "int" olarak tanıtılır ve bir taşma oluşur. – Alexandros

+0

Bu işe yarayacak. İmzasız bir int, büyülü olarak "imzalı bir int" haline dönüştürülmez. Asla. Güncellemeye bakın. –

+0

@Alexandros: bir "imzasız", tamsayı tanıtımı altında aynı kaldığı için çalışacaktır (6.3.1.1/2, "Tamsayı türünde bir nesne veya ifade (int veya unsigned int dışında) ...". "USHRT_MAX", "int" 'ye dönüştürülmesine rağmen "imzasız" işlenen "int"' e dönüştürülmez.Ayrıca, "olağan aritmetik dönüşümler" çarpma için "unsigned" seçeneğini işaretler. –