dài lâu trong C / C ++


84

Tôi đang thử mã này trên trình biên dịch C ++ của GNU và không thể hiểu hành vi của nó:

#include <stdio.h>;

int main()
{
    int  num1 = 1000000000;
    long num2 = 1000000000;
    long long num3;
    //num3 = 100000000000;
    long long num4 = ~0;

    printf("%u %u %u", sizeof(num1), sizeof(num2), sizeof(num3));
    printf("%d %ld %lld %llu", num1, num2, num3, num4);
    return 0;
}

Khi tôi bỏ ghi chú dòng nhận xét, mã không biên dịch và đang xuất hiện lỗi:

lỗi: hằng số nguyên quá lớn đối với kiểu dài

Tuy nhiên, nếu mã được biên dịch như nó vốn có và được thực thi, nó sẽ tạo ra các giá trị lớn hơn nhiều 10000000000.

Tại sao?


8
Có thể là quá muộn bây giờ nhưng đối với độc giả trong tương lai, tôi đề nghị bạn sử dụng <stdint.h>và sử dụng uint64_t. Để hiển thị giá trị 64 bit,printf( "%" PRIu64 "\n", val);
hăng hái

@enthusiasticgeek <stdint.h>bao gồm,uint64_t a = 0xffffffffffffff; printf( "%" PRIu64 "\n",a ); : error: expected ‘)’ before ‘PRIu64’ printf( "%" PRIu64 "\n",a ); :: warning: spurious trailing ‘%’ in format [-Wformat=] printf( "%" PRIu64 "\n",a );
Herdsman

Câu trả lời:


147

Các chữ cái 100000000000 tạo thành một hằng số nguyên theo nghĩa đen, nhưng giá trị quá lớn đối với kiểu int. Bạn cần sử dụng một hậu tố để thay đổi loại chữ, nghĩa là

long long num3 = 100000000000LL;

Hậu tố LLlàm cho từ thành kiểu long long. C không đủ "thông minh" để kết luận điều này từ loại ở bên trái, loại là thuộc tính của chính nghĩa đen, không phải ngữ cảnh mà nó đang được sử dụng.


47
Quay lại khi câu trả lời này đã được viết nó có lẽ là đúng, nhưng bây giờ tiêu chuẩn C ++ nói rằng loại của một số nguyên nghĩa đen không có hậu tố là người đầu tiên của int, long intlong long int, trong đó giá trị của nó có thể được biểu. [C ++ §2.14.2 / 2] Do đó, bây giờ không cần thêm hậu tố 'LL' vào một ký tự số nguyên quá lớn đối với các kiểu khác.
bames53

8
Lý do đây là một vấn đề trước đây không phải vì C ++ không đủ 'thông minh' để xác định kiểu chữ từ loại biến được gán cho, nó đơn giản là do phần mở rộng trình biên dịch không triển khai số nguyên mở rộng nhập sao cho nó hoạt động tốt với ngôn ngữ chuẩn. C ++ hiện nay có quy định như vậy là bất kỳ loại nguyên mở rộng sẽ tích hợp tốt hơn với các tiêu chuẩn: open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
bames53

4
@unwind Tôi nghĩ câu trả lời nên được chỉnh sửa theo những gợi ý này.
Antonio

26

Thử:

num3 = 100000000000LL;

Và BTW, trong C ++ đây là một phần mở rộng của trình biên dịch, tiêu chuẩn không định nghĩa lâu dài, đó là một phần của C99.


11
Chà, C ++ 11 hiện định nghĩa dài dài
Mohamed El-Nakib

4

Nó phụ thuộc vào chế độ bạn đang biên dịch. long long không phải là một phần của tiêu chuẩn C ++ mà chỉ (thường) được hỗ trợ dưới dạng phần mở rộng. Điều này ảnh hưởng đến loại chữ. Các ký tự số nguyên thập phân không có bất kỳ hậu tố nào luôn có kiểu int nếu int đủ lớn để đại diện cho số, ngược lại thì dài. Nếu con số này thậm chí quá lớn trong thời gian dài, kết quả được xác định bởi thực thi (có thể chỉ là một số kiểu long int đã bị cắt bớt để tương thích ngược). Trong trường hợp này, bạn phải sử dụng hậu tố LL một cách rõ ràng để kích hoạt phần mở rộng dài (trên hầu hết các trình biên dịch).

Phiên bản C ++ tiếp theo sẽ chính thức hỗ trợ dài theo cách mà bạn sẽ không cần bất kỳ hậu tố nào trừ khi bạn muốn rõ ràng buộc kiểu của chữ phải dài ít nhất là dài. Nếu số không thể được biểu diễn trong thời gian dài, trình biên dịch sẽ tự động cố gắng sử dụng dài ngay cả khi không có hậu tố LL. Tôi tin rằng đây cũng là hành vi của C99.


1

mã của bạn biên dịch ở đây tốt (ngay cả khi dòng đó không có chú thích. phải thay đổi nó thành

num3 = 100000000000000000000;

để bắt đầu nhận được cảnh báo.


Trình biên dịch nào? Trong C ++, một ký tự số nguyên là giá trị nhỏ hơn của int hoặc long mà nó phù hợp. Trong C99, nó là giá trị nhỏ nhất của int, long, long long. Vì vậy, khi gắn bó lâu dài với C ++ như một phần mở rộng không chuẩn, có lẽ trình biên dịch của bạn cũng đã áp dụng các quy tắc C99 cho các chữ.
Steve Jessop 22/09/09

gcc phiên bản 4.3.2 (Debian 4.3.2-1.1) trên hệ thống linux 64 bit.
Omry Yadan 22/09/09

@SteveJessop Có lẽ hơi muộn: nhưng dài KHÔNG nhất thiết phải là 64 bit. Hầu hết thời gian là như vậy, nhưng bạn không có gì đảm bảo rằng nó sẽ ở khắp mọi nơi. Đảm bảo duy nhất mà bạn có là nó ít nhất phải lớn bằng một int, đến lượt nó, ít nhất cũng lớn bằng một int ngắn, đến lượt nó, ít nhất cũng lớn bằng một char. Cuối cùng, char được định nghĩa là đủ lớn để đại diện cho mọi ký tự trong bộ mã cơ bản của triển khai (thường là 8-bit).
pauluss86

@ pauluss86: Tôi không nói về sự đảm bảo. Omry nói rằng anh đang sử dụng gcc 4.3.2 trên hệ thống Debian 64 bit. Tôi quan sát thấy rằng điều này giải thích những gì anh ấy đã thấy vì (tôi tình cờ biết như một vấn đề kiến ​​thức chung) gcc được định cấu hình theo mặc định trên các hệ thống như vậy để sử dụng 64 bit longphù hợp với LP64 ABI của hệ điều hành đó.
Steve Jessop

@SteveJessop Tôi không cho rằng nhận xét của bạn là sai! Chỉ chỉ ra rằng giả định rằng độ dài luôn luôn là 64 bit ở khắp mọi nơi, điều không may là nhiều người nghĩ, là nguy hiểm.
pauluss86,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.