typedef sabit uzunluk dizisi


210

24-bit veri türü tanımlamalıyım char[3]. Türü temsil etmek için kullanıyorum . Ben typedef Can char[3]için type24? Bir kod örneğinde denedim. typedef char[3] type24;Başlık dosyamı koydum . Derleyici bundan şikayet etmedi. Ancak void foo(type24 val) {}C dosyamda bir işlev tanımladığımda şikayet etti. Bunun type24_to_int32(type24 val)yerine gibi fonksiyonları tanımlamak istiyorum type24_to_int32(char value[3]).

Yanıtlar:


320

Typedef,

typedef char type24[3];

Ancak, bu muhtemelen çok kötü bir fikirdir, çünkü ortaya çıkan tür bir dizi türüdür, ancak kullanıcıları bunun bir dizi türü olduğunu görmez. İşlev bağımsız değişkeni olarak kullanılırsa, değere göre değil, başvuruya göre iletilir vesizeof için yanlış olur.

Daha iyi bir çözüm

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

Muhtemelen unsigned charbunun yerine kullanmak istersiniz char, çünkü ikincisinin uygulama tanımlı imzası vardır.


10
Typedef'ed dizileri parametre olarak geçirmeyle ilgili köşe durumlarını tanımlayan güzel bir belge var mı? Bir işlev bir parametre alır Örneğin, type24 foone boyutları, türleri ve anlamları olacağını foo, *foo, **foo, &foo, ve &&foo? Bu tür ifadelerin anlamları ve yasallığı yıllar içinde değişti mi?
supercat

4
24 bitlik bir veri türü, RGB görüntü verileri gibi farklı tanımlanmış paketleme anlamlarına sahip bir şeyle eşleşmesi amaçlanabilir.
sh1

2
@ sh1: Farkında olduğum tüm modern gerçek dünyadaki ABI'lerde - yanlış hizalanmış erişimin çok pahalı olduğu yerlerde bile - yapılar, üyelerin yapı olmadan sahip olacağından daha güçlü hizalama gereksinimleri almaz. Elbette OP veya bu yaklaşımı kullanan herhangi biri, programlarının davranışı ve taşınabilirliği için önemli olup olmadığını iddia etmemi doğrulamalıdır.
R .. GitHub BUZA YARDIMCI DURDUR

4
@R .. Bunun bir kısmı yanıltıcıdır - C'de, diziler her zaman referans olarak geçirilir, yani bir işleve bağımsız değişken olarak geçirilen diziyi değiştirirseniz, bunu yalnızca işlevin bağlamında değil, küresel olarak yaparsınız. Bununla birlikte, C dizilerinde her zaman değere göre geçirildiği iddia edilebilir, çünkü biz sadece callee yığını üzerindeki yığına kopyalanan ilk elemanın adresini geçiyoruz. Ancak her iki durumda da cevap yanıltıcıdır.
baibo

1
@bobbogo: Bu paketleme değil, sadece bedava dolguların yerleştirilmemesi. Yapının hizası, sadece 1 hizasına sahip üyelerinden herhangi birinin maksimum hizalamasıdır.
R. .. GitHub DURDURMA BUZU

49

İstediğiniz

typedef char type24[3];

C tipi bildirimler bu şekilde gariptir. Bu türdeki bir değişkeni bildiriyorsanız, türü tam olarak değişken adının nereye koyacağını siz koyarsınız.


33

Gönderen R .. 'ın cevabı :

Ancak, bu muhtemelen çok kötü bir fikirdir, çünkü ortaya çıkan tür bir dizi türüdür, ancak kullanıcıları bunun bir dizi türü olduğunu görmez. Bir işlev bağımsız değişkeni olarak kullanılırsa, değere göre değil referansla iletilir ve bunun için sizeof yanlış olur.

Bir dizi olduğunu görmeyen kullanıcılar büyük olasılıkla böyle bir şey yazacaktır (başarısız olur):

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

Aşağıdaki uyarılarla derlenecektir:

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

Ve aşağıdaki çıktıyı üretir:

0
1
-453308976
32767

13

Diziler, C cinsinden değere göre işlev parametreleri olarak geçirilemez.

Diziyi bir yapıya koyabilirsiniz:

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

ve sonra bunu değere göre geçirin, ancak elbette kullanmak daha az uygundur: x.byte[0]yerinex[0] .

İşleviniz type24_to_int32(char value[3])aslında değere göre değil, işaretçiye göre geçer. Tam olarak eşdeğerdir type24_to_int32(char *value)ve3 yok sayılır.

Eğer pointer ile mutlu geçmesini iseniz, olabilir dizisi ile sopa ve yapın:

type24_to_int32(const type24 *value);

Bu, işaretçi-ilk-öğeyi değil, işaretçi-diziyi geçirir, böylece onu şu şekilde kullanırsınız:

(*value)[0]

Bunun gerçekten bir kazanç olduğundan emin değilim, çünkü yanlışlıkla yazarsanız value[1]aptalca bir şey olur.


2
Bence bu cevap bir decayyerde terimden bahsedilerek geliştirilebilir (ve belki de durumun dizileri döndürmek için daha kötü olduğuna işaret ederek - ki bu hiç işe yaramaz).
Frerich Raabe

9

Dizi türünü bir işlev bağımsız değişkeni veya şablon parametresi olarak düzgün bir şekilde kullanmak için, typedef yerine bir yapı yapın, ardından operator[]diziyi aşağıdaki gibi işlevsellik gibi tutabilmek için yapıya bir ekleyin :

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

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

14
Bu bir C sorusudur, C ++ değil. Ne char&de operator[]C. mevcut özelliklerdir
Michael Morris

3

İşte typedef dizisinin neden kafa karıştırıcı olabileceğini gösteren kısa bir örnek. Diğer yanıtlar bir çözüm sağlar.

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

Bu çıktıyı üretir

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

çünkü parametre olarak type24 bir göstericidir. (C'de, diziler her zaman işaretçi olarak geçirilir.) Gcc8 derleyicisi, neyse ki, varsayılan olarak bir uyarı verir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.