mảng chiều dài cố định typedef


209

Tôi phải xác định loại dữ liệu 24 bit. Tôi đang sử dụng char[3]để thể hiện loại. Tôi có thể typedef char[3]để type24? Tôi đã thử nó trong một mẫu mã. Tôi đặt typedef char[3] type24;trong tập tin tiêu đề của tôi. Trình biên dịch đã không phàn nàn về nó. Nhưng khi tôi xác định một hàm void foo(type24 val) {}trong tệp C của mình, nó đã phàn nàn. Tôi muốn có thể xác định các chức năng như type24_to_int32(type24 val)thay vì type24_to_int32(char value[3]).

Câu trả lời:


319

Typedef sẽ là

typedef char type24[3];

Tuy nhiên, đây có lẽ là một ý tưởng rất tồi, bởi vì kiểu kết quả là một kiểu mảng, nhưng người dùng của nó sẽ không thấy rằng đó là một kiểu mảng. Nếu được sử dụng như một đối số hàm, nó sẽ được truyền bằng tham chiếu, không phải bởi giá trị và sizeofsau đó nó sẽ bị sai.

Một giải pháp tốt hơn sẽ là

typedef struct type24 { char x[3]; } type24;

Bạn có thể cũng muốn được sử dụng unsigned charthay vì char, vì sau này có chữ ký được xác định theo triển khai.


10
Có tài liệu hay nào mô tả các trường hợp góc liên quan đến việc truyền các mảng được đánh dấu dưới dạng tham số không? Ví dụ, nếu một hàm nhận một tham số type24 foo, những gì sẽ là kích cỡ, chủng loại, và ý nghĩa của foo, *foo, **foo, &foo, và &&foo? Ý nghĩa và tính hợp pháp của bất kỳ biểu thức nào như vậy đã thay đổi qua nhiều năm?
supercat

4
Có lẽ đáng để đề cập đến cảnh báo đóng gói cấu trúc, vì loại dữ liệu 24 bit có thể được dự định để ánh xạ tới một cái gì đó với ngữ nghĩa đóng gói được xác định khác nhau như dữ liệu hình ảnh RGB.
sh1

2
@ sh1: Trên tất cả các ABI trong thế giới thực hiện đại mà tôi biết - ngay cả những nơi mà việc truy cập không chính xác rất tốn kém - các cấu trúc không nhận được yêu cầu căn chỉnh mạnh hơn các thành viên của chúng nếu không có cấu trúc. Tất nhiên OP hoặc bất kỳ ai khác sử dụng phương pháp này sẽ xác minh khiếu nại của tôi nếu nó có vấn đề với hành vi và tính di động của chương trình của họ.
R .. GitHub DỪNG GIÚP ICE

4
@R .. Một phần của điều này là sai lệch - trong C, các mảng luôn được truyền bằng tham chiếu, nghĩa là, nếu bạn sửa đổi mảng được truyền dưới dạng đối số cho hàm, bạn làm như vậy trên toàn cầu, không chỉ trong ngữ cảnh của hàm. Điều này đang được nói, người ta cũng có thể lập luận rằng trong mảng C luôn luôn được truyền theo giá trị vì chúng ta chỉ cần truyền địa chỉ của phần tử đầu tiên, được sao chép vào ngăn xếp trên ngăn xếp callee. Trong cả hai trường hợp, tuy nhiên, câu trả lời là sai lệch.
baibo

1
@bobbogo: Đó không phải là đóng gói, nó chỉ không chèn miếng đệm vô cớ. Căn chỉnh của cấu trúc chỉ là căn chỉnh tối đa của bất kỳ thành viên nào, tất cả đều có căn chỉnh 1.
R .. GitHub DỪNG GIÚP ICE

49

Bạn muốn

typedef char type24[3];

Khai báo kiểu C là lạ theo cách đó. Bạn đặt loại chính xác nơi tên biến sẽ đi nếu bạn khai báo một biến của loại đó.


32

Từ R .. 's câu trả lời :

Tuy nhiên, đây có lẽ là một ý tưởng rất tồi, bởi vì kiểu kết quả là một kiểu mảng, nhưng người dùng của nó sẽ không thấy rằng đó là một kiểu mảng. Nếu được sử dụng làm đối số hàm, nó sẽ được truyền bằng tham chiếu, không phải theo giá trị và sizeof cho nó sẽ bị sai.

Người dùng không thấy rằng đó là một mảng rất có thể sẽ viết một cái gì đó như thế này (không thành công):

#include <stdio.h>

typedef int twoInts[2];

void print(twoInts *twoIntsPtr);
void intermediate (twoInts twoIntsAppearsByValue);

int main () {
    twoInts a;
    a[0] = 0;
    a[1] = 1;
    print(&a);
    intermediate(a);
    return 0;
}
void intermediate(twoInts b) {
    print(&b);
}

void print(twoInts *c){
    printf("%d\n%d\n", (*c)[0], (*c)[1]);
}

Nó sẽ biên dịch với các cảnh báo sau:

In function intermediate’:
warning: passing argument 1 of print from incompatible pointer type [enabled by default]
    print(&b);
     ^
note: expected int (*)[2]’ but argument is of type int **’
    void print(twoInts *twoIntsPtr);
         ^

Và tạo ra đầu ra sau:

0
1
-453308976
32767

13

Mảng không thể được truyền dưới dạng tham số hàm theo giá trị trong C.

Bạn có thể đặt mảng trong một cấu trúc:

typedef struct type24 {
    char byte[3];
} type24;

và sau đó chuyển nó theo giá trị, nhưng tất nhiên sau đó nó ít thuận tiện hơn để sử dụng: x.byte[0]thay vì x[0].

Hàm của bạn type24_to_int32(char value[3])thực sự đi qua con trỏ, không phải theo giá trị. Nó chính xác tương đương với type24_to_int32(char *value), và 3bị bỏ qua.

Nếu bạn hài lòng khi đi qua con trỏ, bạn có thể sử dụng mảng và thực hiện:

type24_to_int32(const type24 *value);

Điều này sẽ truyền một con trỏ đến mảng, không phải con trỏ đến phần tử đầu tiên, vì vậy bạn sử dụng nó như:

(*value)[0]

Tôi không chắc đó thực sự là một lợi ích, vì nếu bạn vô tình viết value[1]thì có điều gì đó ngu ngốc xảy ra.


2
Tôi nghĩ rằng câu trả lời này có thể được cải thiện bằng cách đề cập đến thuật ngữ decayở đâu đó (và có thể bằng cách chỉ ra rằng tình hình tồi tệ hơn khi trả về mảng - hoàn toàn không hoạt động).
Frerich Raabe

9

Để sử dụng đúng kiểu mảng làm đối số hàm hoặc tham số mẫu, tạo cấu trúc thay vì typedef, sau đó thêm một operator[]cấu trúc để bạn có thể giữ mảng như chức năng như vậy:

typedef struct type24 {
  char& operator[](int i) { return byte[i]; }
  char byte[3];
} type24;

type24 x;
x[2] = 'r';
char c = x[2];

14
Đây là một câu hỏi C, không phải C ++. Không char&phải operator[]những thứ tồn tại trong C.
Michael Morris

3

Đây là một ví dụ ngắn về lý do tại sao mảng typedef có thể không nhất quán một cách khó hiểu. Các câu trả lời khác cung cấp một cách giải quyết.

#include <stdio.h>
typedef char type24[3];

int func(type24 a) {
        type24 b;
        printf("sizeof(a) is %zu\n",sizeof(a));
        printf("sizeof(b) is %zu\n",sizeof(b));
        return 0;
}

int main(void) {
        type24 a;
        return func(a);
}

Điều này tạo ra đầu ra

sizeof(a) is 8
sizeof(b) is 3

bởi vì type24 là một tham số là một con trỏ. (Trong C, các mảng luôn được truyền dưới dạng con trỏ.) Trình biên dịch gcc8 sẽ đưa ra cảnh báo theo mặc định, rất may.

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.