Why Not Mix Signed and Unsigned Values in C/C++?Most C/C++ programmers dịch - Why Not Mix Signed and Unsigned Values in C/C++?Most C/C++ programmers Việt làm thế nào để nói

Why Not Mix Signed and Unsigned Val

Why Not Mix Signed and Unsigned Values in C/C++?
Most C/C++ programmers have been told to avoid mixing signed and unsigned values in expressions. However — at least in part because we usually follow this advice — many of us are not totally on top of the underlying issues. This program illustrates what can go wrong:

#include
int main (void)
{
long a = -1;
unsigned b = 1;
printf ("%d
", a > b);
return 0;
}
Here’s what happens on an x86-64 Linux box:

[regehr@gamow ~]$ gcc compare.c -o compare
[regehr@gamow ~]$ ./compare
0
[regehr@gamow ~]$ gcc -m32 compare.c -o compare
[regehr@gamow ~]$ ./compare
1
In other words, the inequality is false on x64 and true on x86. If this doesn’t give you at least one brief moment of “WTF?” then you’re doing a lot better than I did the first time I saw something like this happen.

The underlying issue is a feature interaction. The first feature is C’s integer promotion strategy, which preserves values but often does not preserve signedness. Usually, the arguments to any arithmetic operator are promoted to signed int — or to a larger signed type, if necessary, to make the operands have the same size. However, if the type contains values not representable in the signed promoted type, the promoted type is instead unsigned. For example, unsigned char and unsigned short can both be promoted to int because all of their values can be represented in an int. On the other hand, unsigned int cannot be promoted to int because (assuming ints are 32 bits) values like 2147483648 are not representable.

The second feature is C’s method for choosing which version of an operator to use. Although the greater-than operator in C always looks like “>”, behind the scenes there are quite a few different operators: signed integer >, unsigned integer >, signed long >, unsigned long >, etc. If either operand to “>” is unsigned, then an unsigned comparison is used, otherwise the comparison is signed.

Now, to return to the example: on a 64-bit platform, b is promoted to signed long and the signed “>” is used. On a 32-bit platform, because “int” and “long” are the same size, b remains unsigned, forcing the unsigned “>” to be used. This explains the reversal of the sense of the comparison.

Sign problems can sneak into code in two additional ways. First, it’s easy to forget that constants are signed by default, even when they are used in a context that seems like it should be unsigned. Second, the result of a comparison operator is always an int: a signed type.

Once we’re aware of these issues, it’s not hard to think through a puzzle like the one above. On the other hand, it can be very difficult to debug this kind of problem in a large piece of software, especially since sign problems are probably not the first item on our list of suspected root causes for a bug.

When writing new software, it’s definitely prudent to turn on compiler warnings about sign problems. Unfortunately, GCC 4.4 doesn’t warn about the program above even when given the -Wall option. The -Wsign-compare option does give a warning, but only when generating 32-bit code. When generating 64-bit code, there’s no warning since b is promoted to a signed type before being exposed to the “>” operator. So if we’re primarily developing on the 64-bit platform, the problem may remain latent for a while.

Just to make things extra confusing, one time I tracked down a problem where the version of GCC that was released as part of Ubuntu Hardy for x86 miscompiled a function very similar to the one above. It took this program and compiled it to return 1:

int foo (void) {
signed char a = 1;
unsigned char b = -1;
return a > b;
}
Here both values should be promoted to signed int and the comparison is then (1 > 255). Obviously, in this case the compiler was buggy. The base version of GCC, 4.2.2, does not have this bug. However, the Ubuntu people applied about 5 MB of patches to this compiler before packaging it up and somehow broke it. A few years ago I found similar bugs in CIL and in an early version of Clang. Apparently even compiler developers are not immune to signed/unsigned confusion.

0/5000
Từ: -
Sang: -
Kết quả (Việt) 1: [Sao chép]
Sao chép!
Tại sao không pha trộn chữ ký và dấu các giá trị trong C/c ++?Hầu hết các lập trình C/c ++ đã được cho biết để tránh trộn ký và dấu các giá trị trong biểu hiện. Tuy nhiên — tại ít nhất một phần bởi vì chúng tôi thường làm theo lời khuyên này-nhiều người trong chúng ta là không hoàn toàn trên đầu trang của các vấn đề cơ bản. Chương trình này minh họa những gì có thể đi sai:#include int chính (vô hiệu){ dài một = -1; dấu b = 1; printf ("%d
", một > b); trở về 0;}Dưới đây là những gì sẽ xảy ra trên một hộp Linux x 86-64:[regehr@gamow ~] $ gcc compare.c -o so sánh[regehr@gamow ~] $. / so sánh0[regehr@gamow ~] $ gcc-m32 compare.c -o so sánh[regehr@gamow ~] $. / so sánh1Nói cách khác, bất đẳng thức là sai trên sự thật trên x 86 và x 64. Nếu điều này không cung cấp cho bạn ít nhất một thời điểm ngắn gọn của "WTF?", sau đó bạn đang làm rất nhiều hơn tôi đã lần đầu tiên tôi thấy một cái gì đó như thế này xảy ra.Vấn đề cơ bản là một tính năng tương tác. Các tính năng đầu tiên là C của số nguyên chiến lược khuyến mãi, mà giữ giá trị nhưng thường không bảo tồn signedness. Thông thường, các đối số cho bất kỳ nhà điều hành phép tính số học được phát huy để ký int- hoặc một loại ký lớn hơn, nếu cần thiết, để làm cho operands có cùng kích thước. Tuy nhiên, nếu các loại có chứa giá trị không USD trong loại khuyến khích đầu tư ký, loại khuyến khích đầu tư là thay vì dấu. Ví dụ, unsigned char và dấu ngắn có thể cả hai được đẩy mạnh để int bởi vì tất cả các giá trị có thể được biểu diễn trong một int. Mặt khác, unsigned int không thể được đẩy mạnh để int vì (giả định một là 32 bit) giá trị như 2147483648 là không USD.Các tính năng thứ hai là C của phương pháp cho việc lựa chọn phiên bản nào của một nhà điều hành để sử dụng. Mặc dù lớn hơn-hơn nhà điều hành trong luôn luôn trông giống như ">", đằng sau hậu trường có khá một vài nhà khai thác khác nhau: ký số nguyên >, đánh dấu số nguyên >, dài ký >, dấu lâu >, vv. Nếu một trong hai operand để ">" là unsigned, sau đó một so sánh dấu được sử dụng, nếu không so sánh được ký kết.Bây giờ, để trở về mẫu: trên một nền tảng 64-bit, b đang xúc tiến để ký hợp đồng dài và các ký ">" được sử dụng. Trên một nền tảng 32-bit, bởi vì "int" và "dài" là cùng kích thước, b vẫn chưa được ký, buộc các dấu ">" được sử dụng. Điều này giải thích đảo ngược ý nghĩa của việc so sánh.Vấn đề đăng nhập có thể lẻn vào mã theo hai cách bổ sung. Đầu tiên, nó rất dễ dàng để quên rằng hằng số được ký kết theo mặc định, ngay cả khi chúng được sử dụng trong một bối cảnh đó có vẻ như nó nên được đánh dấu. Thứ hai, kết quả của một nhà điều hành so sánh luôn luôn là một int: một loại ký.Một khi chúng tôi nhận thức được những vấn đề này, nó không phải là khó để suy nghĩ thông qua một trò chơi giống như một ở trên. Mặt khác, nó có thể rất khó khăn để gỡ lỗi các loại của các vấn đề trong một mảnh lớn của phần mềm, đặc biệt là kể từ khi vấn đề đăng nhập có thể không là mục đầu tiên trên danh sách của chúng tôi nghi ngờ gốc nguyên nhân cho một lỗi.Khi viết phần mềm mới, nó là chắc chắn thận trọng để bật trình biên dịch cảnh báo về vấn đề đăng nhập. Thật không may, GCC 4.4 không cảnh báo về chương trình trên ngay cả khi cho-tùy chọn tường. Tùy chọn - Wsign-so sánh cung cấp cho một cảnh báo, nhưng chỉ khi tạo ra 32-bit mã. Khi tạo ra 64-bit mã, có là không có cảnh báo kể từ khi b đang xúc tiến đến một loại ký trước khi được tiếp xúc với các ">" nhà điều hành. Vì vậy, nếu chúng ta đang chủ yếu phát triển trên nền tảng 64-bit, vấn đề có thể vẫn còn tiềm ẩn trong một thời gian.Chỉ để làm cho mọi việc thêm khó hiểu, một thời gian tôi theo dõi xuống một vấn đề mà các phiên bản của GCC đã được phát hành như một phần của Ubuntu Hardy cho x 86 miscompiled một chức năng rất tương tự như một ở trên. Nó đã cho chương trình này và biên dịch nó trở về 1:int foo (vô hiệu) {} ký char một = 1; unsigned char b = -1; trở về một > b;}Ở đây cả hai giá trị cần được đẩy mạnh để ký int và so sánh là sau đó (1 > 255). Rõ ràng, trong trường hợp này trình biên dịch đã là buggy. Phiên bản cơ bản của GCC, 4.2.2, không có lỗi này. Tuy nhiên, Ubuntu người áp dụng khoảng 5 MB của bản vá lỗi cho trình biên dịch này trước khi đóng gói nó lên và bằng cách nào đó đã phá vỡ nó. Một vài năm trước đây tôi tìm thấy lỗi tương tự như ở CIL và phiên bản đầu tiên của kêu vang. Dường như nhà phát triển trình biên dịch thậm chí không được miễn dịch với ký/unsigned nhầm lẫn.
đang được dịch, vui lòng đợi..
Kết quả (Việt) 2:[Sao chép]
Sao chép!
Tại sao không trộn các giá trị đã ký và Unsigned trong C / C ++?
Hầu hết các C / C ++ lập trình viên đã được cho biết để tránh pha trộn các giá trị đã ký kết và unsigned trong các biểu thức. Tuy nhiên - ít nhất là trong một phần bởi vì chúng ta thường làm theo lời khuyên này - nhiều người trong chúng ta không hoàn toàn trên đầu trang của các vấn đề tiềm ẩn. Chương trình này minh họa những gì có thể đi sai: #include


int main (void)
{
dài a = -1;
unsigned b = 1;
printf ("% d n", a> b);
return 0;
}
Đây là những gì xảy ra trên một x86-64 Linux hộp: [Regehr @ Gamow ~] $ gcc -o compare.c so sánh [Regehr @ Gamow ~] $ ./compare 0 [Regehr @ Gamow ~] $ gcc -o -m32 compare.c so sánh [Regehr @ Gamow ~] $ ./compare 1 Trong khác lời nói, sự bất bình đẳng là sai trên x64 và đúng sự thật trên x86. Nếu điều này không cung cấp cho bạn ít nhất một thời gian ngắn của "WTF?", Sau đó bạn đang làm tốt hơn rất nhiều so với tôi đã lần đầu tiên tôi nhìn thấy một cái gì đó như thế này xảy ra. Vấn đề cơ bản là một tính năng tương tác. Tính năng đầu tiên là chiến lược xúc tiến số nguyên C, mà bảo tồn các giá trị nhưng thường không giữ gìn signedness. Thông thường, các đối số cho bất kỳ toán tử số học được thăng int ký - hoặc một loại ký lớn hơn, nếu cần thiết, để làm cho các toán hạng có cùng kích thước. Tuy nhiên, nếu loại chứa các giá trị không biểu diễn trong thúc đẩy loại ký, loại thăng tiến là thay vì unsigned. Ví dụ, unsigned char và unsigned ngắn đều có thể được thăng int bởi vì tất cả các giá trị của họ có thể được đại diện trong một int. Mặt khác, unsigned int không có thể được thúc đẩy để int vì (ints giả định là 32 bit) giá trị như 2147483648 không phải là biểu diễn. Tính năng thứ hai là phương pháp C để lựa chọn phiên bản của một nhà điều hành để sử dụng. Mặc dù lớn hơn điều hành trong C luôn luôn trông giống như ">", đằng sau hậu trường có khá một vài nhà khai thác khác nhau: số nguyên ký kết>, số nguyên không dấu>, ký dài>, unsigned dài>, vv Nếu một trong hai toán hạng để "> ". là unsigned, sau đó một sự so sánh không dấu được sử dụng, nếu không so sánh được ký Bây giờ, quay trở lại ví dụ: trên một nền tảng 64-bit, b được thúc đẩy để ký kết lâu dài và ký kết ">" được sử dụng. Trên một nền tảng 32-bit, bởi vì "int" và "dài" có cùng kích thước, b vẫn unsigned, buộc các dấu ">" để được sử dụng. Điều này giải thích sự đảo chiều của cảm giác so sánh. Đăng ký các vấn đề có thể lẻn vào mã trong hai cách bổ sung. Đầu tiên, nó dễ dàng để quên rằng các hằng ký theo mặc định, ngay cả khi chúng được sử dụng trong một bối cảnh mà có vẻ như nó phải là unsigned. Thứ hai, kết quả của một toán tử so sánh luôn luôn là một int:. Một loại ký Một khi chúng ta đang nhận thức được những vấn đề này, nó không khó để suy nghĩ thông qua một câu đố như trên. Mặt khác, nó có thể rất khó khăn để gỡ lỗi các loại vấn đề trong một mảnh lớn của phần mềm, đặc biệt là kể từ khi vấn đề dấu hiệu có lẽ không phải là mục đầu tiên trong danh sách những nguyên nhân nghi ngờ gốc cho một lỗi. Khi viết phần mềm mới, đó là chắc chắn thận trọng để bật cảnh báo trình biên dịch về vấn đề dấu. Thật không may, GCC 4.4 không cảnh báo về các chương trình trên ngay cả khi cung cấp tùy chọn Wall. Các tùy chọn -Wsign-so sánh không đưa ra cảnh báo, nhưng chỉ khi tạo mã 32-bit. Khi tạo mã 64-bit, không có cảnh báo kể từ b được thăng một loại ký trước khi được tiếp xúc với ">" nhà điều hành. Vì vậy, nếu chúng ta đang phát triển chủ yếu trên nền tảng 64-bit, vấn đề có thể vẫn còn tiềm ẩn trong một thời gian. Chỉ cần để làm cho mọi việc thêm khó hiểu, một lần tôi theo dõi xuống một vấn đề mà các phiên bản của GCC đã được phát hành như là một phần của Ubuntu Hardy cho x86 miscompiled một chức năng rất tương tự như trên. Phải mất chương trình này và biên dịch nó để trở về 1: int foo (void) { ký char a = 1; unsigned char b = -1; trở lại a> b; } Ở đây cả hai giá trị cần được thúc đẩy để int ký và sau đó so sánh là (1> 255). Rõ ràng, trong trường hợp này là các trình biên dịch lỗi. Phiên bản cơ sở của GCC, 4.2.2, không có lỗi này. Tuy nhiên, người dân Ubuntu áp dụng khoảng 5 MB của bản vá lỗi cho trình biên dịch này trước khi đóng gói nó lên và bằng cách nào đó đã phá vỡ nó. Một vài năm trước, tôi thấy lỗi tương tự trong CIL và trong phiên bản đầu tiên của Clang. Rõ ràng, ngay cả các nhà phát triển trình biên dịch không được miễn dịch để ký / unsigned nhầm lẫn.






























đang được dịch, vui lòng đợi..
 
Các ngôn ngữ khác
Hỗ trợ công cụ dịch thuật: Albania, Amharic, Anh, Armenia, Azerbaijan, Ba Lan, Ba Tư, Bantu, Basque, Belarus, Bengal, Bosnia, Bulgaria, Bồ Đào Nha, Catalan, Cebuano, Chichewa, Corsi, Creole (Haiti), Croatia, Do Thái, Estonia, Filipino, Frisia, Gael Scotland, Galicia, George, Gujarat, Hausa, Hawaii, Hindi, Hmong, Hungary, Hy Lạp, Hà Lan, Hà Lan (Nam Phi), Hàn, Iceland, Igbo, Ireland, Java, Kannada, Kazakh, Khmer, Kinyarwanda, Klingon, Kurd, Kyrgyz, Latinh, Latvia, Litva, Luxembourg, Lào, Macedonia, Malagasy, Malayalam, Malta, Maori, Marathi, Myanmar, Mã Lai, Mông Cổ, Na Uy, Nepal, Nga, Nhật, Odia (Oriya), Pashto, Pháp, Phát hiện ngôn ngữ, Phần Lan, Punjab, Quốc tế ngữ, Rumani, Samoa, Serbia, Sesotho, Shona, Sindhi, Sinhala, Slovak, Slovenia, Somali, Sunda, Swahili, Séc, Tajik, Tamil, Tatar, Telugu, Thái, Thổ Nhĩ Kỳ, Thụy Điển, Tiếng Indonesia, Tiếng Ý, Trung, Trung (Phồn thể), Turkmen, Tây Ban Nha, Ukraina, Urdu, Uyghur, Uzbek, Việt, Xứ Wales, Yiddish, Yoruba, Zulu, Đan Mạch, Đức, Ả Rập, dịch ngôn ngữ.

Copyright ©2025 I Love Translation. All reserved.

E-mail: