2012-10-21 30 views
7

Câu hỏi của tôi bắt nguồn từ việc cố gắng sử dụng printf để ghi lại mọi thứ khi cố gắng xây dựng cho nhiều nền tảng có độ sâu bit (ví dụ: 32/64).Có nguy hiểm khi quảng bá các loại trong đối số printf không?

Một vấn đề tiếp tục nuôi đầu xấu xí của nó là cố gắng in ints trên nhiều kiến ​​trúc. Trên 32 bit nó sẽ là một cái gì đó giống như

printf(" my int: %d\n", myInt); 

nhưng trên 64 bit, nó sẽ phải được thay đổi để

print (" my int: %ld\n", (long)myInt); 

Tôi có hai câu hỏi liên quan:

  1. Suy nghĩ đầu tiên của tôi đó là khi bạn yêu cầu printf in một biến, cho nó một định dạng, nó sẽ xem xét địa chỉ của biến đó và lấy nhiều byte vì nó cần cho định dạng đó. Điều này dường như là một vấn đề lớn lúc đầu. Ví dụ nếu bạn có một biến myChar là một char (1 byte), nhưng sử dụng một định dạng specifier của% d, điều đó sẽ cho printf đi đến địa chỉ myChar và lấy 4 byte tiếp theo để xử lý nó như một int. Nếu đây là trường hợp, có vẻ như printf sẽ lấy ngày rác từ các biến lân cận (vì nó đã lấy 4 byte, nhưng giá trị thực chỉ là 1 byte). Điều này dường như không phải là trường hợp tuy nhiên. Bằng cách sử dụng myChar và chỉ định% d, printf lấy 1 byte và sau đó đệm 3 byte trên bằng 0. Sự hiểu biết của tôi có đúng ở đây không?

  2. Nếu điều trên đúng, có bất kỳ tác hại thực sự nào trong việc luôn thúc đẩy các biến lên tới giá trị lớn nhất của chúng để tránh các loại sự cố được nhìn thấy trong trường hợp bit 32/64 hay không. Ví dụ: nếu bạn có biến myShort ngắn và biến int, myInt, có bất kỳ nhược điểm nào trong việc in chúng luôn như sau:

    printf ("myShort% ld", (long) myShort); printf ("myInt% ld", (dài) myInt);

Cảm ơn bạn đã giải thích rõ.

+0

bản sao có thể có của [Tự động loại khuyến mãi trong hàm variadic] (http://stackoverflow.com/questions/7084857/automatic-type-promotion-in-variadic-function) –

+1

IMO, không thực sự gần với câu hỏi song công . Tôi sẽ khuyến khích mọi người tiếp tục thảo luận ở đây thay vì bỏ phiếu để đóng cửa. –

+3

Tại sao bạn tin rằng 'printf ("% d ", myInt);' phải được thay đổi cho nền tảng 64 bit? –

Trả lời

6

Liên quan đến printf: Trong trường hợp bạn đặt, "% d" phải, theo đặc điểm kỹ thuật, xử lý loại dữ liệu 'int' được nền tảng xác định. Nó không quan trọng cho dù đó là 32 bit, 64 bit, hoặc 128 bit tuyến tính AS/400 giá trị. Nếu bạn muốn quảng cáo giá trị cho loại trường lớn hơn (và khớp với quảng cáo đó với hạt chuỗi định dạng có liên quan), bạn chắc chắn sẽ tự do làm như vậy,

int a=0; 
printf("%ld", (long)a); 

chắc chắn được xác định bằng cách sử dụng quảng cáo.

Tôi nghĩ điểm mấu chốt thực sự của câu hỏi của bạn xuất hiện trong các trường hợp như sau, và liệu việc thúc đẩy có thể "giải quyết" bất kỳ vấn đề nào phát sinh hay không.Ví dụ:

char ch = 'a'; 
printf("%d", ch); 

hoặc những gì về:

char ch = 'a'; 
printf("%ld", (long)ch); 

hoặc có lẽ đây (đó là điều kiện thực tế bạn dường như cố gắng để tránh):

char ch = 'a'; 
printf("%ld", ch); 

Đầu tiên trong số này sẽ hoạt động, nhưng chỉ vì kích thước tối thiểu của bất kỳ thứ gì được xếp chồng lên danh sách va-arg là kích thước nền tảng của int. Trình biên dịch sẽ tự động quảng cáo giá trị cho một int cho bạn. Vì "% d" dự kiến ​​nền tảng int tất cả sẽ xuất hiện tốt.

Cách thứ hai sẽ hoạt động luôn là và được hỗ trợ đầy đủ. Có quảng cáo rõ ràng và được xác định từ char đến long. Ngay cả khi long là 64 bit (hoặc lớn hơn), nó vẫn hoạt động.

Thứ ba là UB tất cả các cách. printf đang tìm kiếm một long và sẽ chỉ hiển thị các byte cho một số int. Nếu điều này có vẻ "hoạt động" trên nền tảng của bạn, hãy kiểm tra chiều rộng nền tảng của bạn cho intlong. Có khả năng là "hoạt động" chỉ vì nền tảng của bạn longint có cùng chiều rộng bit. Nó làm cho những điều ngạc nhiên thú vị khi chuyển mã sang nền tảng nơi chúng không chạy, và vì nó được đẩy qua va-arg, bạn sẽ không thấy nó cho đến khi thực độ rộng khác nhau được phát.

Tất cả điều đó đang được nói, bây giờ hãy ném một địa chỉ thực tế vào thứ gì đó (bất kỳ thứ gì, thực sự) như yêu cầu của scanf và chúng tôi đang xem một thứ hoàn toàn khác.

int val; 
sscanf("%ld",&val); 

Đây là lỗi chờ đợi xảy ra. Giống như trên, bạn sẽ không bao giờ biết điều đó nếu nền tảng của bạn long và nền tảng int có cùng chiều rộng. Đưa mã này vào một ô có số longint là các kích thước khác nhau và tự chuẩn bị trước cho tải gdb của tệp lõi tiếp theo.

0

bools/_Bools, charsshorts lần đầu tiên được chuyển đổi thành int (nếu chuyển đổi này bảo tồn giá trị, nếu không vào unsigned int) khi thông qua chức năng variadic như printf(). Tương tự, floats được chuyển đổi thành doubles.

Vì vậy, nếu bạn vượt qua một cái gì đó nhỏ hơn int, printf() sẽ lấy toàn bộ (unsigned) int mà không cần bất kỳ vấn đề (trừ nếu giá trị thông qua thực sự là một unsigned int và bạn đang in nó với %d thay vì %u, bạn sẽ có được hành vi undefined).

Các loại khác, AFAIR, không trải qua các chuyển đổi như vậy.

dòng này:

print (" my int: %ld\n", (long)myInt); 

không mua bất cứ thứ gì trên dòng này:

printf(" my int: %d\n", myInt); 

Cả hai đều hợp lệ và kết quả sẽ là thực tế giống hệt nhau. Sự khác biệt duy nhất là trước đây có thể dẫn đến mã lớn hơn và thời gian thực hiện lâu hơn (nếu sizeof(long) >= sizeof(int)).

0
  1. Đối số được chuyển trong ngăn xếp, có chiều rộng cố định (32 hoặc 64) bit cho mỗi mục nhập. Trình biên dịch 'mô tả' các số nguyên, ký tự, quần short với chiều rộng bản địa của kiến ​​trúc hoặc trong trường hợp của một đôi (hoặc dài) tại 32 kiến ​​trúc, nó phân bổ hai khe từ ngăn xếp. Các "padding" được thực hiện hoặc với zeroes, hoặc bit dấu của biến được sao chép vào các bit còn lại. (Gọi tắt là chút mở rộng dấu)

  2. Một nhược điểm trong việc thúc đẩy tới 64 bit là thiếu tính tương thích trong hệ thống nhúng, mà thường không cung cấp in 64-bit. Ngoài ra nó có nghĩa là trong hệ thống 32-bit một số hình phạt hiệu suất như 32-bit đầu luôn luôn được thông qua và chuyển đổi (có một phân chia rộng 64 bit bởi 10 tham gia) mà không có bất kỳ sử dụng thực sự. Tuy nhiên, vấn đề lớn hơn là rơi vào miền của kĩ nghệ phần mềm: nhật ký "tương thích trong tương lai" đưa ra một hy vọng sai lầm rằng tất cả tính toán và tất cả đầu vào cho hệ thống hoạt động ở chế độ 64 bit trên các hệ thống 32 bit.

(dài) trong kiến ​​trúc 32 bit không có nghĩa là 64 bit. Đó là ký hiệu với (dài lâu).

1

Bạn nói:

Một vấn đề mà giữ nhô đầu xấu xí của nó đang cố gắng in ints trên nhiều kiến ​​trúc

Có nguy hiểm để thử và nhận trước các vấn đề loại bằng cách đi qua trong các giá trị không thuộc loại kích thước đó, có. Đó là lý do tại sao trình biên dịch cảnh báo bạn. Khái niệm về tính di động mà dường như gây ra cho bạn các vấn đề không được thiết kế để làm cho printf hạnh phúc.

Được thiết kế để chương trình của bạn chạy và không bị lỗi trên nhiều kiến ​​trúc. Nếu bạn có mã nền tảng cụ thể, bạn nên sử dụng #ifdef macro để làm việc xung quanh nó.

Nếu không, bạn đang lăn con xúc xắc đang cố gắng phân lớp trên chuyển đổi loại cấp bộ nhớ.

printf là một tiện ích không phải là phương pháp chuyển đổi loại.

Có vẻ như bạn đang tập trung vào ints - điều mà bạn có thể sẽ bỏ qua. Nhưng nói chung tôi sẽ không dựa vào một kỹ thuật như thế này.

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