2012-01-19 37 views
5

tôi đã gặp phải lỗi trong một số mã c tôi đã viết và trong khi tương đối dễ sửa, tôi muốn có thể hiểu vấn đề cơ bản tốt hơn. về cơ bản những gì đã xảy ra là tôi có hai số nguyên không dấu (uint32_t, trên thực tế), khi hoạt động mô đun được áp dụng, mang lại số tương đương chưa ký của một số âm, một số đã được bọc và do đó "lớn". đây là một chương trình ví dụ để chứng minh:tràn chưa được ký với toán tử mô-đun trong C

#include <stdio.h> 
#include <stdint.h> 

int main(int argc, char* argv[]) { 

    uint32_t foo = -1; 
    uint32_t u = 2048; 
    uint64_t ul = 2048; 

    fprintf(stderr, "%d\n", foo); 
    fprintf(stderr, "%u\n", foo); 
    fprintf(stderr, "%lu\n", ((foo * 2600000000) % u)); 
    fprintf(stderr, "%ld\n", ((foo * 2600000000) % u)); 
    fprintf(stderr, "%lu\n", ((foo * 2600000000) % ul)); 
    fprintf(stderr, "%lu\n", foo % ul); 

    return 0; 

} 

này xuất ra như sau, trên máy x86_64 của tôi:

-1 
4294967295 
18446744073709551104 
-512 
1536 
2047 

1536 là số tôi đã mong đợi, nhưng (uint32_t) (- 512) là số tôi đã nhận được, mà, như bạn có thể tưởng tượng, đã ném những thứ ra một chút.

vì vậy, tôi đoán câu hỏi của tôi là: tại sao hoạt động mô-đun giữa hai số không dấu, trong trường hợp này, tạo ra số lớn hơn số chia (nghĩa là số âm)? có lý do nào khiến hành vi này được ưa thích hơn không?

+1

2600000000 là một int (hoặc có thể là 64-bit int - dài hoặc dài dài), mà có thể đã gây ra kết quả của phép nhân để trở thành một (ký) dài. Bạn đang sử dụng nền tảng nào? – Random832

Trả lời

3

Tôi nghĩ lý do là trình biên dịch được giải thích 2600000000 đen như một số 64-bit đã ký, vì nó không phù hợp với một ký 32-bit int. Nếu bạn thay số bằng 2600000000U, bạn sẽ nhận được kết quả mong đợi.

+2

Thực ra OP đã gọi UB bằng cách truyền các chuỗi định dạng sai tới 'printf'. –

2

Tôi không có tham chiếu tiện dụng, nhưng tôi khá chắc chắn khi bạn thực hiện phép nhân đó, nó sẽ kích hoạt chúng thành int64_t, vì nó cần phải ép buộc hai phép nhân thành một loại tích phân có dấu. Hãy thử 2600000000u thay vì 2600000000 ....