2010-08-02 23 views
8

Mã sau đây có 100% di động không?Cách thay thế kích thước máy tính của một loại sử dụng số học con trỏ

int a=10; 
size_t size_of_int = (char *)(&a+1)-(char*)(&a); // No problem here? 

std::cout<<size_of_int;// or printf("%zu",size_of_int); 

P.S: Câu hỏi chỉ dành cho mục đích học tập. Vì vậy, xin đừng cho câu trả lời như Use sizeof() vv

+0

di động với những gì? int không phải là nền tảng độc lập và có ý nghĩa khác trong các hệ thống 64bit. Mặc dù C++ của tôi có lẽ là quá gỉ vì điều này. – Blub

+0

@Blub: Ý tôi là kích thước in mã luôn luôn ở trên (int) (ví dụ: 4 trên môi trường 32 bit điển hình)? –

+1

cho các hồ sơ, bạn có thể vui lòng chọn một tiêu đề phù hợp cho câu hỏi của bạn? cái gì đó ít nhất đề cập đến số học con trỏ. cảm ơn –

Trả lời

13

Từ ANSI-ISO-IEC 14882-2003, tr.87 (C++ 03):

"75) Một cách khác để tiếp cận con trỏ số học là đầu tiên để chuyển đổi con trỏ (s) để con trỏ ký tự (s): Trong Đề án này giá trị không thể thiếu của biểu thêm vào hoặc trừ vào con trỏ chuyển đổi là lần đầu tiên nhân với kích thước của đối tượng ban đầu chỉ vào, và dẫn con trỏ được chuyển đổi trở lại loại ban đầu. Đối với con trỏ trừ, kết quả của sự khác biệt giữa các ký tự poin ters tương tự được chia cho kích thước của đối tượng ban đầu chỉ được . "

Điều này dường như gợi ý rằng sự khác biệt con trỏ bằng với kích thước đối tượng.

Nếu chúng ta loại bỏ các UB'ness từ incrementing một con trỏ đến một vô hướng a và biến thành một mảng:

int a[1]; 
size_t size_of_int = (char*)(a+1) - (char*)(a); 

std::cout<<size_of_int;// or printf("%zu",size_of_int); 

Sau đó, điều này có vẻ OK. Các mệnh đề về yêu cầu căn chỉnh phù hợp với chú thích, nếu yêu cầu căn chỉnh luôn chia hết cho kích thước của đối tượng.

CẬP NHẬT: Thú vị. Như hầu hết các bạn có thể biết, GCC cho phép chỉ định một sự liên kết rõ ràng với các kiểu như một phần mở rộng. Nhưng tôi không thể phá vỡ phương pháp "sizeof" của OP với nó vì GCC từ chối biên dịch nó:

#include <stdio.h> 

typedef int a8_int __attribute__((aligned(8))); 

int main() 
{ 
a8_int v[2]; 

printf("=>%d\n",((char*)&v[1]-(char*)&v[0])); 
} 

Thư này là error: alignment of array elements is greater than element size.

+2

Nếu bạn thay thế '& a [1]' bằng '& a [0] + 1' hoặc' a + 1', một mảng có kích thước 1 là đủ, bởi vì nó là hợp pháp để chỉ một đầu-cuối-của một mảng. Ngoài ra, bạn nên thay thế '& [0]' bằng '& a [0]' hoặc 'a' ;-) – fredoverflow

+0

@Fred: Cảm ơn bạn! –

+0

+1 cho câu trả lời đúng về mặt kỹ thuật. @FredOverflow: Trong C99 '& a [1]' và 'a + 1' chỉ giống nhau. :) –

1

Tại sao không chỉ:

size_t size_of_int = sizeof(int); 
+2

Điều đó không trả lời được câu hỏi của tôi. Tôi biết chúng ta có toán tử 'sizeof()' cho mục đích đó. Câu hỏi chỉ dành cho mục đích học tập. :) –

4

&a+1 sẽ dẫn đến hành vi không xác định theo quy định của C++ chuẩn 5,7/5:

Khi một biểu thức có kiểu tích phân được thêm vào hoặc trừ khỏi một con trỏ, kết quả có kiểu là toán hạng con trỏ. < ...> Nếu cả toán hạng con trỏ và điểm kết quả cho các phần tử của cùng một đối tượng mảng hoặc một phần tử cuối cùng của đối tượng mảng, thì việc đánh giá sẽ không tạo ra tràn; nếu không, hành vi là không xác định.

&a+1 là OK theo 5,7/4:

Theo mục đích của các nhà khai thác, một con trỏ đến một đối tượng nonarray cư xử giống như một con trỏ đến yếu tố đầu tiên của một mảng chiều dài một với loại đối tượng làm loại phần tử của đối tượng.

Điều đó có nghĩa là 5.7/5 có thể được áp dụng mà không cần UB. Và cuối cùng nhận xét 75 từ 5,7/6 như @Luther Blissett lưu ý trong câu trả lời của mình nói rằng mã trong câu hỏi là hợp lệ.


Trong mã sản xuất, bạn nên sử dụng sizeof để thay thế. Nhưng tiêu chuẩn C++ không đảm bảo rằng sizeof(int) sẽ dẫn đến 4 trên mọi nền tảng 32 bit.

+0

IMHO hợp lệ theo 'Nếu cả toán tử con trỏ và điểm kết quả đến các phần tử của cùng một đối tượng mảng hoặc một phần tử cuối cùng của đối tượng mảng, ...' '& a + 1' con trỏ điểm một trong quá khứ kết thúc đó là hợp lệ và có thể sử dụng con trỏ. – wilx

+0

Bạn nên thay thế '& a [1]' bằng '& a [0] + 1' hoặc' a + 1', vì trước đây có thể dẫn đến [hành vi chưa xác định] (http://stackoverflow.com/questions/3144904/may -i-take-the-địa chỉ-của-một-qua-the-end-yếu tố-of-an-mảng-đóng). – fredoverflow

0

Đoạn mã trên sẽ tính toán được sizeof(int) trên nền tảng đích nhưng sau đó được triển khai xác định - bạn sẽ nhận được kết quả khác nhau trên các nền tảng khác nhau.

1

Có thể là việc triển khai đã được xác định.

Tôi có thể tưởng tượng một hệ thống (giả thuyết) trong đó sizeof (int) nhỏ hơn căn chỉnh mặc định.

Có vẻ chỉ an toàn để nói rằng size_of_int >= sizeof(int)

0

Vâng, nó mang lại cho bạn tương đương với sizeof(a) nhưng sử dụng ptrdiff_t thay vì size_t loại.

0

Đã có cuộc tranh luận về số similar question.

Xem nhận xét trên my answer cho câu hỏi đó để biết một số gợi ý tại sao điều này không chỉ không mang tính di động mà còn là hành vi không xác định theo tiêu chuẩn.

2

No. Mã này sẽ không hoạt động như bạn mong đợi trên mọi plattform. Ít nhất là về lý thuyết, có thể có một plattform với ví dụ Số nguyên 24 bit (= 3 byte) nhưng căn chỉnh 32 bit. Sự sắp xếp như vậy không phải là không điển hình đối với các plattforms (cũ hơn hoặc đơn giản hơn). Sau đó, mã của bạn sẽ trả về 4, nhưng sizeof (int) sẽ trả về 3.

Nhưng tôi không biết phần cứng thực sự hoạt động theo cách đó. Trong thực tế, mã của bạn sẽ hoạt động trên hầu hết hoặc tất cả các plattforms.

+2

-1, trên các nền tảng như vậy 'sizeof (int)' là 4. Tuy nhiên, 8 trong số 32 bit đó sẽ không tham gia vào biểu diễn giá trị của int. Chỉ cho (unsigned) char bạn có được sự bảo đảm rằng tất cả các bit tham gia vào đại diện giá trị. (Có, bạn không thể ghi nhớ những điều). – MSalters

2

Đó không phải là 100% xách tay vì những lý do sau đây:

  1. Chỉnh sửa: Bạn muốn tốt nhất sử dụng int a[1]; và sau đó a+1 trở nên dứt khoát hợp lệ.
  2. & gọi hành vi không xác định trên đối tượng của lớp lưu trữ đăng ký.
  3. Trong trường hợp hạn chế căn chỉnh lớn hơn hoặc bằng kích thước của int, size_of_int sẽ không chứa câu trả lời đúng.

Disclaimer:

Tôi không chắc chắn nếu các tổ chức trên cho C++.

+0

+1 để lưu ý về UB & đăng ký. Mặc dù nếu bạn đang sử dụng đăng ký (vì lý do tốt), bạn chắc chắn biết về sizeof và bất kỳ mối quan tâm di chuyển liên quan. –

+0

Nó không bao giờ UB. Trong C nó bị hỏng (yêu cầu chẩn đoán) và trong C++ nó được cho phép (trình biên dịch sicne bỏ qua nó anyway). – MSalters

+0

@MSalters: Tôi cho rằng bạn đang nói về (1)? Nó, trên thực tế, - sau khi thực sự đề cập đến các tiêu chuẩn - theo ngữ nghĩa cho các nhà khai thác phụ gia thực sự là OK. Tôi không thể tìm thấy nơi nó được coi là hình thành bệnh. Bạn có thể giúp? –

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