2015-05-18 18 views
5

Làm việc trên mảnh này ít mã trong VS2013, nhưng đối với một số lý do nó không print.it vẻ như -1> strlen (str)tại sao -1> strlen (t) đúng trong C?

Bất cứ ai có một ý tưởng những gì tôi đang làm sai

char *str="abcd"; 
if(-1<strlen(str)) 
printf("The size of the string is %d", strlen(str));  
return 0; 
+1

giá trị đầu ra của 'strlen (str)' là gì? – sasquatch

+1

Có thể là nó trả về giá trị unsigned và phá vỡ mọi thứ –

+2

nó là tốt để bật cảnh báo để tối đa cài đặt trên trình biên dịch của bạn –

Trả lời

10

Bất cứ ai có một ý tưởng những gì tôi đang làm sai

strlen() trả về một size_t, mà là một kiểu dữ liệu integer unsigned. -1 được hiểu là một số nguyên không dấu là một giá trị lớn, vì vậy nó kết thúc bằng cách lớn hơn độ dài của chuỗi của bạn. Bạn có thể sử dụng cờ -Wsign-compare trong gcc và một số trình biên dịch khác để cảnh báo bạn khi bạn cố so sánh các giá trị đã ký và chưa ký.

Ngoài ra, không có ý nghĩa gì khi so sánh độ dài của chuỗi với -1. Độ dài không bao giờ có thể âm; nó là luôn luôn sẽ là 0 trở lên. Vì vậy, có thể bạn sẽ muốn viết lại mã của mình để kiểm tra theo số 0 hoặc thực hiện đúng cách bất kỳ điều kiện nào bạn đang cố gắng kiểm tra.

if(-1<strlen(str)) printf("The size of the string is %d", strlen(str));

Trong mã này, bạn có thể hợp lý mong đợi những thử nghiệm để luôn thành công và printf() để thực hiện, vì chiều dài luôn là 0 trở lên. Nhưng bạn thấy rằng thử nghiệm thực sự không thành công và printf() không bao giờ xảy ra vì -1 được thăng hạng thành unsigned để nó có thể được so sánh với size_t. Các giải pháp dễ dàng là để loại bỏ hoàn toàn điều kiện: bạn biết thử nghiệm sẽ luôn thành công, vì vậy không cần thiết cho nó. Chỉ cần loại bỏ các if*:

printf("The size of the string is %zu", strlen(str)); 

* Ngoài ra, thay đổi sự xác định định dạng in từ %d để %zu vì, như Matt McNabb đã chỉ ra trong một chú thích, bạn đang cố gắng in một size_t.

+1

Bạn có thể nói với OP về cảnh báo trình biên dịch, nếu được bật, ngăn chặn loại lỗi này. – chqrlie

+0

@chqrlie Đề xuất tốt; làm xong. – Caleb

+1

Cảm ơn bạn rất nhiều! –

4

strlen(str) trả về một số nguyên không dấu. Khi so sánh số nguyên đã ký với số nguyên không dấu, trình biên dịch chuyển đổi giá trị đã ký thành unsigned. Khi được chuyển thành unsigned, -1 trở thành 2^32 - 1 (giả sử rằng strlen trả về số nguyên 32 bit), lớn hơn độ dài của chuỗi mà bạn đang so sánh.

+1

Đừng cho rằng 'size_t' dài 32 bit. – Caleb

+0

Bạn có thể nói với OP về cảnh báo trình biên dịch, nếu được bật, ngăn chặn loại lỗi này. – chqrlie

+0

Chuyển đổi là 'size_t', không phải là' int'. 'strlen' trả về' size_t' và nó là khá phổ biến những ngày này cho rằng được nhiều hơn 32 bit. – juanchopanza

4

strlen trả về giá trị loại size_t. Đây là loại tích phân không dấu.

Quy tắc trong C khi so sánh giá trị đã ký với giá trị của loại chưa ký tương ứng, là giá trị đã ký được chuyển thành giá trị chưa ký.

Nếu giá trị có các loại có kích thước khác nhau, ví dụ: nếu hệ thống của bạn có 4 byte int và 8 byte size_t thì quy tắc là giá trị của loại nhỏ hơn được chuyển thành giá trị của loại lớn hơn.

Dù bằng cách nào, điều này có nghĩa là -1 được chuyển thành size_t, dẫn đến SIZE_MAX là giá trị dương lớn. (loại không dấu không thể giữ giá trị âm).

Giá trị dương lớn này lớn hơn độ dài của chuỗi của bạn, vì vậy, so sánh nhỏ hơn trả về false.

+0

Bạn có thể nói với OP về cảnh báo trình biên dịch, nếu được bật, ngăn chặn loại lỗi này. – chqrlie

+0

@chqrlie phụ thuộc vào chất lượng của trình biên dịch và cài đặt. Tôi có xu hướng vô hiệu hóa cảnh báo đã ký-unsigned vì chúng là những mặt tích cực sai thường xuyên hơn không. –

+0

Cảm ơn bạn rất nhiều! –

Các vấn đề liên quan