2010-06-22 44 views
10

Tôi biết C++ và tự biết chức năng sizeof nhưng tôi cần viết hàm sizeof của riêng tôi vì vậy hãy giải thích cách hoạt động chính xác? Nó làm gì với tham số?Sizeof hoạt động như thế nào? Làm thế nào tôi có thể viết của riêng tôi?

+17

'sizeof' không phải là hàm, đó là toán tử đặc biệt ánh xạ các loại thành số nguyên tại thời gian biên dịch. – fredoverflow

+0

ok và cách thực hiện nó theo chức năng sao cho thực hiện công việc giống như sizeof? –

+8

@davit câu trả lời là bạn * không thể *, ít nhất là không sử dụng 'sizeof' hiện có. Nó không phải là một cái gì đó có thể được thực hiện trong thời gian chạy. –

Trả lời

25

Bạn chưa cung cấp bất kỳ chi tiết có ý nghĩa nào về việc bạn muốn làm gì, vì vậy thật khó để tìm ra những gì bạn cần.

Bạn có thể "quấn" sizeof bởi bạn chức năng template riêng như

template <typename T> size_t my_sizeof() { 
    return sizeof(T); 
} 

và sau đó sử dụng nó như

size_t s = my_sizeof<int>(); 

Từ bất cứ lúc nào người ta có thể đi qua một yêu cầu để thực hiện sizeof giống như chức năng mà không cần sử dụng sizeof. Các yêu cầu như thế không có ý nghĩa thực tế, nhưng đôi khi được sử dụng như bài tập về nhà. Người ta có thể làm điều đó như sau

template <typename T> size_t my_sizeof() { 
    T t; 
    return (char *) (&t + 1) - (char *) &t; 
} 

yêu cầu cấu hình mặc định T. Một giải pháp ít động ngăn cản nhưng chính thức bất hợp pháp (một hack) sẽ là một cái gì đó giống như

template <typename T> size_t my_sizeof() { 
    return (char *) ((T *) NULL + 1) - (char *) (T *) NULL; 
} 

Việc triển khai thực hiện trên loại dựa trên sizeof.

Một cố gắng để bắt chước các chức năng của giá trị dựa trên sizeof có thể trông như sau

template <typename T> size_t my_sizeof(const T& obj) { 
    return my_sizeof<T>(); 
} 

nhưng điều này sẽ không được thậm chí từ xa tương đương với built-in sizeof, nếu ít nhất vì được xây dựng trong sizeof không đánh giá đối số của nó.

Cuối cùng, không phải triển khai nào trong số này sẽ tạo ra các biểu thức hằng số không đổi (ICE), như được xây dựng trong sizeof. Sản xuất một ICE theo cách đó là không thể đạt được trong phiên bản hiện tại của ngôn ngữ.

Trong mọi trường hợp, tất cả điều này, tất nhiên, hoàn toàn không có giá trị thực tiễn nào. Chỉ cần sử dụng sizeof khi bạn muốn biết kích thước.

+2

bài tập về nhà khá ngu ngốc để bọc sizeof() nếu bạn hỏi tôi –

+0

Tôi nghĩ về char * hack quá. Một bài tập ngớ ngẩn thực sự. – Reinderien

+1

Tất nhiên thực tế là công trình này hoàn toàn phụ thuộc vào thời gian biên dịch bất biến 'sizeof (char) == 1', mà là một chút của một catch-22. –

31

sizeof là trình biên dịch được tích hợp sẵn trình biên dịch. Nó được đánh giá tại thời gian biên dịch bởi trình biên dịch, và không có mã thời gian chạy đằng sau nó. Bạn không thể viết của riêng bạn.

Hỏi điều này cũng giống như việc hỏi bạn sẽ viết phiên bản return của riêng mình như thế nào.

+0

Tuy nhiên, bạn có thể tạo một trình bao bọc * cho 'sizeof', có thể là những gì OP cần. Khó để nói mà không có bối cảnh nhiều hơn nữa. –

+0

ok cảm ơn tôi hiểu –

+0

Sự nhầm lẫn của anh ấy là dễ hiểu, vì bạn * có thể * ghi đè lên mới/xóa. –

1

sizeof không phải là chức năng và bạn không thể viết phiên bản của riêng mình. Trình biên dịch làm việc ra loại đối số (trừ khi nó đã là một kiểu), sau đó thay thế biểu thức bằng một hằng số nguyên.

4

Như đã nói nó là một nhà điều hành không phải là một chức năng, nhưng bổ sung nó là một trong những nhà khai thác mà nhà điều hành quá tải không được phép:

Bjarne Stroustrup's C++ Style and Technique FAQ: Why can't I overload dot, ::, sizeof, etc.?

tôi có thể nghĩ không có lý do có thể tưởng tượng tại sao bạn sẽ muốn quá tải điều này trong mọi trường hợp.Nếu bạn có một lớp có thông tin về kích thước khác với thông tin về số lượng sizeof, thì chỉ cần thêm một hàm thành viên để cung cấp thông tin đó; ví dụ như trong std::string:size() trả về độ dài của chuỗi được đối tượng quản lý thay vì kích thước của đối tượng khác ngữ nghĩa; bạn không muốn khỉ với ngữ nghĩa của sizeof!

0

Nếu anh ta muốn viết kích thước của riêng mình, anh ta chỉ cần lấy mã nguồn của trình biên dịch C++ và tiếp tục. Nguồn cũng sẽ cho thấy cách sizeof có thể được thực hiện.

+0

Nó có thể sẽ được thực hiện bằng cách sử dụng các cấu trúc dữ liệu bên trong trình biên dịch mà không thể truy cập thông qua nguồn C++. –

+0

Bạn hiểu lầm tôi. Lời khuyên của tôi là tạo một trình biên dịch đã sửa đổi từ một nguồn trình biên dịch hiện có. Điều này có thể rất mang tính giáo dục. –

7

Một cách không cầm tay để viết sizeof của riêng bạn() chức năng là để tận dụng lợi thế về cách biến ngăn xếp dựa trên thường được đặt ra trong bộ nhớ:

#include <iostream> 
using namespace std; 

template <typename T> 
int mysizeof(T) 
{ 
    T temp1; 
    T temp2; 

    return (int)&temp1 - (int)&temp2; 
} 

int main() 
{ 
    cout << "sizeof mysizeof" << endl; 

    char c = 0; short s = 0; int i = 0; long l = 0; 
    float f = 0; double d = 0; long double ld = 0; 

    cout << "char: " << mysizeof(c) << endl; 
    cout << "short: " << mysizeof(s) << endl; 
    cout << "int: " << mysizeof(i) << endl; 
    cout << "long: " << mysizeof(l) << endl; 
    cout << "float: " << mysizeof(f) << endl; 
    cout << "double: " << mysizeof(d) << endl; 
    cout << "long double: " << mysizeof(ld) << endl; 
} 

See it in action.
A 0-parameter version.
A version that uses one array instead of two variables.

Cảnh báo: Đây là một câu đố thú vị, nhưng bạn không bao giờ nên sử dụng nó trong mã thực. sizeof được đảm bảo hoạt động. Đây không phải là. Chỉ vì nó hoạt động trên phiên bản này của trình biên dịch này cho nền tảng này không có nghĩa là nó sẽ làm việc cho bất kỳ khác.

Toán tử thực sự tận dụng lợi thế của việc trở thành một phần của trình biên dịch. Sizeof biết mỗi loại biến lớn như thế nào bởi vì nó phải biết. Nếu trình biên dịch không biết mức độ lớn của từng loại, nó sẽ không thể đặt chương trình của bạn ra ngoài trong bộ nhớ.

Chỉnh sửa: Lưu ý rằng tất cả các ví dụ không hoàn thiện này dựa trên toán tử sizeof gốc. Nó được sử dụng để không gian các biến ngăn xếp, và để tạo và lập chỉ mục các biến mảng.

+4

Có lẽ sẽ an toàn hơn khi có một mảng gồm hai mục, thay vì đếm trên trình biên dịch để đặt người dân địa phương theo một thứ tự nhất định. mảng [1] luôn xuất hiện sau mảng [0] và với phần đệm thích hợp. –

+0

@dash: Tôi cũng nghĩ về điều đó, nhưng bị phân tâm. Tôi đã cập nhật câu trả lời của mình với một liên kết đến triển khai dựa trên mảng. – Bill

+1

Cả hai việc triển khai đều không hoạt động trên một lớp trừu tượng hoặc một lớp thiếu một hàm tạo tham số công khai, bằng 0. – jmucchiello

0

sizeof được đánh giá tại thời điểm biên dịch (BoostLoki tận dụng nó). Vì vậy, tôi nghĩ rằng, nó là không thể viết sizeof - chức năng khiếu nại cho đệm được cấp phát động.

2

sizeof là toán tử C++ mang lại số byte trong biểu diễn đối tượng của toán hạng. Kết quả của sizeof là hằng số được xác định bởi loại size_t, nhưng phải đáp ứng các yêu cầu được quy định trong tiêu chuẩn C++ 5.3.3. Bạn có thể viết các đặc điểm kiểu của riêng bạn sẽ hoạt động tương tự như toán tử được xây dựng trong sizeof.

template<typename T> struct get_sizeof; 

template<> struct get_sizeof<char>   { static const size_t value = 1; }; 
template<> struct get_sizeof<unsigned char> { static const size_t value = 1; }; 
template<> struct get_sizeof<int>   { static const size_t value = 4; }; 
template<> struct get_sizeof<long>   { static const size_t value = 4; }; 
// etc. 

... 
// sample of use 
static const size_t size = get_sizeof<int>::value; 
char x[get_sizeof<int>::value]; 

Nhưng điều này không có ý nghĩa vì chỉ người tạo trình biên dịch mới biết giá trị thực tế của value để triển khai.

0

sizeof không phải là chức năng. Đó là một nhà điều hành trong C. Chúng ta có thể thực hiện chức năng của nó như sau.

#include <stdio.h> 

#define mysizeof(X) \ 

      ({     \ 
        __typeof(X) x; \ 
        (char *) (&x+1) - (char*) (&x); \ 
      }) 
int main() 
{ 

    struct sample 
    { 
     int a;float b; char c; 
    }; 

    printf("%d", mysizeof(struct sample)); 
    return 0; 
} 

Trả lời: 12

1

Tôi thấy bài này khi tìm kiếm một cách để có được những chức năng tương tự như các nhà điều hành sizeof. Hóa ra là tôi đã thực hiện một hàm gọi là bit_sizeof() trông giống như toán tử sizeof, nhưng nó trả về số bit của một kiểu đã cho thay vào đó. Tôi đã triển khai chức năng mẫu chung như sau:

#include <limits.h> //For CHAR_BIT 

//Global function bit_sizeof() 
template<typename TSizeOfType> 
constexpr uint32_t bit_sizeof(TSizeOfType) 
{ 
    return (sizeof(TSizeOfType) * CHAR_BIT); 
} 

Chức năng này yêu cầu sử dụng tiêu chuẩn C++ 11 vì sử dụng từ khóa constexpr.Nếu không có từ khóa constexpr, hàm sẽ vẫn biên dịch. Nhưng trình biên dịch có thể không tối ưu hóa đúng cách và đưa vào một cuộc gọi hàm tại mỗi trang gọi bằng cách sử dụng hàm bit_sizeof. Với việc sử dụng constexpr, toàn bộ hàm đánh giá một hằng số, mà trong kiến ​​thức của tôi phải chính xác tương đương với cách toán tử sizeof hoạt động như thế nào? Đúng nếu tôi đã sai lầm. Trong sử dụng tôi gọi hàm như thế này, với một parantesis thêm vào sau khi loại:

uint32_t uiBitsInType = bit_sizeof(char()); 

Chức năng có thể hữu ích khi tạo mặt nạ bit cho ví dụ:

uint32_t uiMask = (((uint32_t(0x1) << bit_sizeof(char())) - 0x1) << bit_sizeof(char())); 

Mà có thể là dễ đọc hơn so này :

uint32_t uiMask2 = (((uint32_t(0x1) << (sizeof(char) * 0x8)) - 0x1) << (sizeof(char) * 0x8)); 

Cá nhân tôi cũng có sử dụng khác cho chức năng này.

+0

Bạn có thể muốn kiểm tra 'CHAR_BIT'. Ngoài ra, '_T' là một tiền tố dành riêng cho các tên được xác định thực hiện. Chỉ cần thả các mẫu '_', C++ không phải là macro. Chúng tuân theo phạm vi, do đó, 'typename TSizeOfType' chỉ hiển thị bên trong khuôn mẫu. – MSalters

+0

Ồ, cảm ơn. Tôi đã thực hiện các thay đổi như bạn đã đề xuất. – Peter

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