typedef array ความยาวคงที่


210

ฉันต้องกำหนดประเภทข้อมูล 24 บิตฉันใช้char[3]เพื่อแสดงประเภท ฉันสามารถ typedef char[3]เพื่อtype24? ฉันลองในตัวอย่างรหัส ฉันใส่typedef char[3] type24;ไฟล์ส่วนหัว คอมไพเลอร์ไม่ได้บ่นเกี่ยวกับมัน แต่เมื่อฉันกำหนดฟังก์ชั่นvoid foo(type24 val) {}ในไฟล์ C ของฉันมันก็บ่น ฉันต้องการที่จะสามารถที่จะกำหนดฟังก์ชั่นเช่นแทนtype24_to_int32(type24 val)type24_to_int32(char value[3])

คำตอบ:


320

typedef จะเป็น

typedef char type24[3];

อย่างไรก็ตามนี่อาจเป็นความคิดที่แย่มากเพราะประเภทผลลัพธ์เป็นประเภทอาร์เรย์ แต่ผู้ใช้จะไม่เห็นว่าเป็นประเภทอาร์เรย์ หากใช้เป็นอาร์กิวเมนต์ฟังก์ชันจะถูกส่งผ่านโดยการอ้างอิงไม่ใช่ตามค่าและsizeofสำหรับมันจะผิด

ทางออกที่ดีกว่าก็คือ

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

คุณอาจต้องการใช้unsigned charแทนcharเนื่องจากภายหลังมีการลงนามที่กำหนดการนำไปปฏิบัติ


10
มีเอกสารที่ดีที่อธิบายถึงกรณีมุมที่เกี่ยวข้องกับการผ่านอาร์เรย์ typedef'ed เป็นพารามิเตอร์? ตัวอย่างเช่นถ้าฟังก์ชั่นใช้เวลาพารามิเตอร์type24 fooสิ่งที่จะเป็นขนาดประเภทและความหมายของfoo, *foo, **foo, &fooและ&&foo? ความหมายและความชอบด้วยกฎหมายของการแสดงออกดังกล่าวมีการเปลี่ยนแปลงในช่วงหลายปีที่ผ่านมา?
supercat

4
น่าจะพูดถึงโครงสร้างการบรรจุข้อควรระวังเนื่องจากชนิดข้อมูล 24 บิตอาจมีวัตถุประสงค์เพื่อแมปกับสิ่งที่บรรจุซีแมนทิกส์ที่กำหนดแตกต่างกันเช่นข้อมูลภาพ RGB
sh1

2
@ sh1: ใน ABIs โลกแห่งความเป็นจริงที่ทันสมัยทั้งหมดฉันตระหนักถึง - แม้กระทั่งที่การเข้าถึงที่ไม่ตรงแนวมีราคาแพงมาก - โครงสร้างไม่ได้รับความต้องการการจัดตำแหน่งที่แข็งแกร่งกว่าสมาชิกของพวกเขาจะไม่มีโครงสร้าง แน่นอนว่า OP หรือใครก็ตามที่ใช้วิธีนี้ควรตรวจสอบการอ้างสิทธิ์ของฉันหากมันมีความสำคัญต่อพฤติกรรมของโปรแกรมและการพกพา
. GitHub หยุดช่วยน้ำแข็ง

4
@R .. ส่วนหนึ่งของสิ่งนี้คือการทำให้เข้าใจผิด - ใน C อาร์เรย์จะถูกส่งผ่านโดยการอ้างอิงเสมอเช่นถ้าคุณแก้ไขอาร์เรย์ที่ส่งผ่านเป็นอาร์กิวเมนต์ไปยังฟังก์ชันคุณทำเช่นนั้นทั่วโลกไม่เพียง แต่ในบริบทของฟังก์ชั่น สิ่งนี้ถูกกล่าวว่าเราสามารถโต้แย้งได้ว่าในอาร์เรย์ C มักถูกส่งผ่านค่าเนื่องจากเราเพียงแค่ผ่านที่อยู่ขององค์ประกอบแรกซึ่งถูกคัดลอกไปยังสแต็กบนสแต็ก callee อย่างไรก็ตามในทั้งสองกรณีคำตอบนั้นทำให้เข้าใจผิด
baibo

1
@bobbogo: นั่นไม่ใช่การบรรจุมันเป็นเพียงแค่การแทรกช่องว่างที่ไม่มีเหตุผล การจัดตำแหน่งของโครงสร้างเป็นเพียงการจัดตำแหน่งสูงสุดของสมาชิกใด ๆ ซึ่งทั้งหมดมีการจัดตำแหน่ง 1
R. GitHub หยุดช่วยน้ำแข็ง I

49

คุณต้องการ

typedef char type24[3];

การประกาศประเภท C นั้นเป็นวิธีที่แปลก คุณใส่ชนิดที่ชื่อตัวแปรจะไปหากคุณประกาศตัวแปรประเภทนั้น


33

จากR .. 's คำตอบ :

อย่างไรก็ตามนี่อาจเป็นความคิดที่แย่มากเพราะประเภทผลลัพธ์เป็นประเภทอาร์เรย์ แต่ผู้ใช้จะไม่เห็นว่าเป็นประเภทอาร์เรย์ หากใช้เป็นอาร์กิวเมนต์ของฟังก์ชั่นมันจะถูกส่งผ่านโดยการอ้างอิงไม่ใช่ตามค่าและขนาดของมันจะผิด

ผู้ใช้ที่ไม่เห็นว่ามันเป็นอาเรย์มักจะเขียนสิ่งนี้ (ซึ่งล้มเหลว):

#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]);
}

มันจะรวบรวมคำเตือนต่อไปนี้:

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);
         ^

และสร้างผลลัพธ์ต่อไปนี้:

0
1
-453308976
32767

13

อาร์เรย์ไม่สามารถส่งผ่านเป็นพารามิเตอร์ฟังก์ชันตามค่าใน C

คุณสามารถใส่อาเรย์ในโครงสร้าง:

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

แล้วส่งผ่านว่าด้วยค่า แต่แน่นอนแล้วก็ไม่ค่อยสะดวกที่จะใช้: แทนx.byte[0]x[0]

ฟังก์ชั่นของคุณtype24_to_int32(char value[3])ส่งผ่านโดยตัวชี้ไม่ใช่ตามค่า มันเทียบเท่ากับtype24_to_int32(char *value)และ3ถูกละเว้น

หากคุณมีความสุขที่ผ่านตัวชี้คุณสามารถใช้อาร์เรย์และทำสิ่งต่อไปนี้

type24_to_int32(const type24 *value);

สิ่งนี้จะผ่านตัวชี้ไปยังอาร์เรย์ไม่ใช่ตัวชี้ไปยังองค์ประกอบแรกดังนั้นคุณจึงใช้มันเป็น:

(*value)[0]

ฉันไม่แน่ใจว่าเป็นประโยชน์จริง ๆ เพราะถ้าคุณเขียนโดยบังเอิญมีvalue[1]บางสิ่งที่โง่เกิดขึ้น


2
ฉันคิดว่าคำตอบนี้สามารถปรับปรุงได้โดยการพูดถึงคำdecayบางแห่ง (และอาจชี้ให้เห็นว่าสถานการณ์แย่กว่าสำหรับการกลับมาใช้อาร์เรย์ - ซึ่งไม่ได้ผลเลย)
Frerich Raabe

9

ในการใช้ประเภทอาเรย์อย่างถูกต้องเป็นฟังก์ชั่นอาร์กิวเมนต์หรือพารามิเตอร์เทมเพลตให้สร้าง struct แทน typedef จากนั้นเพิ่มoperator[]ไปที่ struct เพื่อให้คุณสามารถคงอาร์เรย์เหมือนฟังก์ชันการทำงานดังนี้

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

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

14
นี่คือคำถาม C ไม่ใช่ C ++ ทั้งchar&มิได้operator[]เป็นสิ่งที่มีอยู่ในซี
ไมเคิลมอร์ริส

3

นี่เป็นตัวอย่างสั้น ๆ ว่าทำไมอาร์เรย์ typedef จึงไม่สอดคล้องกันอย่างสับสน คำตอบอื่น ๆ ให้วิธีแก้ปัญหา

#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);
}

สิ่งนี้สร้างผลลัพธ์

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

เนื่องจาก type24 เป็นพารามิเตอร์เป็นตัวชี้ (ใน C อาร์เรย์จะถูกส่งผ่านเป็นตัวชี้เสมอ) คอมไพเลอร์ gcc8 จะออกคำเตือนตามค่าเริ่มต้นขอบคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.