2017-06-24 49 views
9

Jeśli piszę ogólny algorytm, czy mogę zezwolić na alias tablicy nieznanego typu jako wskaźnika do tablicy, w której każdy element ma rozmiar podany bez wywoływania niezdefiniowanego zachowania?Dostęp do elementów tablicy ogólnie poprzez wskaźnik do tablicy znaków?

Na przykład, czy istnieje UB w następującym kodzie?

typedef void (*action_t)(const void *item); 
void do(void *array, size_t eltCount, size_t eltSize, action_t action) 
{ 

    // Convenient typedef. 
    typedef char element[eltSize]; 
    element *elts = array; 
    element *end = elts + eltCount; 

    for (; elts != end; elts++) { 
     action(elts); 
    } 
} 

wiem, że mogę to zrobić:

char *elts = array; 
char *end = elts + eltCount * eltSize; 

for (; elts != end; elts += eltSize) { 
    action(elts); 
} 

Ale pierwszy kawałek kodu wydaje się bardziej idiomatycznych do mnie, ponieważ kompilator robi arytmetycznych wskaźnika dla mnie. Powyższa funkcja kompiluje się bez ostrzeżeń, używając zarówno gcc, jak i clang (odpowiednie flagi kompilacji to -std=c99 -O3 -fstrict-aliasing -pedantic-errors -Wextra -Wall). Zastanawiam się również nad ścisłym aliasingiem, ale o ile wiem, wydaje mi się, że nie łamie go tutaj, ponieważ obiekty mogą być używane pośrednio przez char*.

+0

W tym ostatnim przykładzie przekazujemy pojedynczy znak do funkcji, która oczekuje przynajmniej unieważnienia wskaźnika. Literówka? –

+0

@ IljaEverilä Naprawiono. Dziękuję –

+0

Jeśli masz kłopoty, to 'qsort()' i 'bsearch()' są zbyt ..., –

Odpowiedz

1

W języku C, typedef nie wprowadza nowego typu. Po prostu nazywa się konstrukt. Nazwa i jej definicja są wymienne. (To samo nie dotyczy np. struct, gdzie nie ma możliwości wyrażenia definicji struktury poza nazwą.)

Tak długo, jak mówisz tylko o jakiejś formie char * - co, jak wiesz, jest wyjątkowe, ponieważ każdy wskaźnik danych można przekonwertować na niego - wtedy polegasz na określonym zachowaniu.