mengetikkan panjang array tetap

210

Saya harus mendefinisikan tipe data 24-bit. Saya menggunakan char[3]untuk mewakili tipe. Dapatkah saya typedef char[3]ke type24? Saya mencobanya dalam contoh kode. Saya memasukkan typedef char[3] type24;file header saya. Kompiler tidak mengeluh tentang hal itu. Tetapi ketika saya mendefinisikan fungsi void foo(type24 val) {}dalam file C saya, itu memang mengeluh. Saya ingin dapat mendefinisikan fungsi seperti type24_to_int32(type24 val)bukan type24_to_int32(char value[3]).

341008
sumber

Jawaban:

320

Ketikan akan menjadi

typedef char type24[3];

Namun, ini mungkin ide yang sangat buruk, karena tipe yang dihasilkan adalah tipe array, tetapi pengguna tidak akan melihat bahwa itu adalah tipe array. Jika digunakan sebagai argumen fungsi, itu akan dilewatkan dengan referensi, bukan oleh nilai, dan sizeofuntuk itu akan salah.

Solusi yang lebih baik

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

Anda mungkin juga ingin menggunakan unsigned charbukan char, karena yang terakhir memiliki penandatanganan yang ditentukan implementasi.

R .. GitHub BERHENTI MEMBANTU ICE
sumber
10
Apakah ada dokumen bagus yang menggambarkan kasus sudut terlibat dengan melewati array typedef'ed sebagai parameter? Misalnya, jika fungsi mengambil parameter type24 foo, apa yang akan menjadi ukuran, jenis, dan makna dari foo, *foo, **foo, &foo, dan &&foo? Sudahkah makna dan legalitas ekspresi semacam itu berubah selama bertahun-tahun?
supercat
4
Mungkin layak menyebutkan peringatan struktur packing, karena tipe data 24-bit mungkin dimaksudkan untuk memetakan sesuatu dengan semantik pengemasan yang berbeda seperti data gambar RGB.
sh1
2
@ sh1: Pada semua ABI dunia nyata modern yang saya sadari - bahkan yang di mana akses yang tidak selaras sangat mahal - struktur tidak mendapatkan persyaratan penyelarasan yang lebih kuat daripada yang dimiliki anggota mereka tanpa struktur. Tentu saja OP atau siapa pun yang menggunakan pendekatan ini harus memverifikasi klaim saya jika itu akan berpengaruh pada perilaku dan portabilitas program mereka.
R .. GitHub BERHENTI MEMBANTU ICE
4
@ R .. Salah satu bagian dari ini menyesatkan - dalam C, array selalu diberikan oleh referensi, yaitu, jika Anda memodifikasi array yang dilewatkan sebagai argumen ke fungsi, Anda melakukannya secara global, tidak hanya dalam konteks fungsi. Ini dikatakan, orang juga bisa berpendapat bahwa dalam array C selalu dilewatkan oleh nilai karena kita hanya melewati alamat elemen pertama, yang disalin ke stack pada stack callee. Namun dalam kedua kasus, jawabannya menyesatkan.
baibo
1
@ Bobbogo: Itu bukan pengepakan, itu hanya non-penyisipan padanan serampangan. Penjajaran struktur hanyalah penyelarasan maksimum dari setiap anggotanya, yang semuanya memiliki penjajaran 1.
R .. GitHub STOP HELPING ICE
49

Kamu ingin

typedef char type24[3];

Deklarasi tipe C aneh seperti itu. Anda meletakkan jenis persis di mana nama variabel akan pergi jika Anda mendeklarasikan variabel jenis itu.

ysth
sumber
33

Dari jawaban R .. :

Namun, ini mungkin ide yang sangat buruk, karena tipe yang dihasilkan adalah tipe array, tetapi pengguna tidak akan melihat bahwa itu adalah tipe array. Jika digunakan sebagai argumen fungsi, argumen akan dilewatkan dengan referensi, bukan oleh nilai, dan ukurannya akan salah.

Pengguna yang tidak melihat bahwa itu adalah sebuah array kemungkinan besar akan menulis sesuatu seperti ini (yang gagal):

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

Ini akan dikompilasi dengan peringatan berikut:

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

Dan menghasilkan output sebagai berikut:

0
1
-453308976
32767
Gerhard Burger
sumber
13

Array tidak dapat dilewatkan sebagai parameter fungsi dengan nilai dalam C.

Anda bisa meletakkan array di struct:

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

dan kemudian berikan nilai, tapi tentu saja itu kurang nyaman untuk digunakan: x.byte[0]alih-alih x[0].

Fungsi Anda type24_to_int32(char value[3])sebenarnya dilewati oleh pointer, bukan oleh nilai. Ini persis sama dengan type24_to_int32(char *value), dan 3diabaikan.

Jika Anda senang melewati pointer, Anda bisa tetap menggunakan array dan melakukan:

type24_to_int32(const type24 *value);

Ini akan melewatkan pointer-to-array, bukan pointer-to-first-element, jadi Anda menggunakannya sebagai:

(*value)[0]

Saya tidak yakin itu benar-benar keuntungan, karena jika Anda tidak sengaja menulis value[1]maka sesuatu yang bodoh terjadi.

Steve Jessop
sumber
2
Saya pikir jawaban ini dapat ditingkatkan dengan menyebutkan istilah decaysuatu tempat (dan mungkin dengan menunjukkan bahwa situasi lebih buruk untuk kembali array - yang tidak bekerja sama sekali).
Frerich Raabe
9

Untuk menggunakan tipe array dengan benar sebagai argumen fungsi atau parameter templat, buat struct sebagai ganti typedef, lalu tambahkan operator[]ke struct agar Anda dapat menjaga fungsionalitas array seperti:

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

type24 x;
x[2] = 'r';
char c = x[2];
Geronimo
sumber
14
Ini adalah pertanyaan C, bukan C ++. Juga char&tidak operator[]ada hal-hal yang ada dalam C.
Michael Morris
3

Berikut adalah contoh singkat mengapa array typedef dapat membingungkan tidak konsisten. Jawaban lain memberikan solusi.

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

Ini menghasilkan output

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

karena type24 sebagai parameter adalah pointer. (Dalam C, array selalu diberikan sebagai pointer.) Kompiler gcc8 akan mengeluarkan peringatan secara default, untungnya.

Daniel
sumber