2012-06-18 18 views
7

Miałem wrażenie, że postinkieta (OR preinkrement) może być wykonana tylko po prawej stronie równej (=). Ale jestem w stanie skompilować poniższy fragment kodu. Czy możesz mi pomóc w zrozumieniu tego kodu, szczególnie pod linią. źródło: http://www.ibm.com/developerworks/library/pa-dalign/postincrement po lewej stronie

*data8++ = -*data8; 


void Munge8(void *data, uint32_t size) { 
    uint8_t *data8 = (uint8_t*) data; 
    uint8_t *data8End = data8 + size; 

    while(data8 != data8End) { 
     *data8++ = -*data8; 
    } 
} 
+0

Przypisanie '- * data8' do' * data8' następnie przyrost 'data8' - skutecznie negując' size' bajtów w 'data' – Erik

Odpowiedz

3

Twoje wrażenie jest źle, myślę. na pewno można zrobić rzeczy jak:

*a++ = *b++; 

w tym, że często jak strcpy jest realizowany. Można nawet mieć post- lub wstępnie przyrosty bez = w ogóle:

a++; 
+0

czekaj, więc byłem w porozumieniu z oryginalnym wpisem. Jak to nie jest niezdefiniowane zachowanie? –

+0

strcpy nie jest jednak zaimplementowany. Najpierw szuka się końca łańcucha w wzorach bitowych większych porcji danych, a następnie kopiuje dane w większych porcjach (zwykle 64-bitowych). –

+0

@sharth: Jak to jest niezdefiniowane? Nie jestem standardowym ćpunem, ale RHS należy najpierw ocenić, a następnie LHS. Dlatego nie powinno być problemów. –

1

Nie ma powodu, dlaczego postinkrementacja nie mogą być wykonane na lewej stronie operatora przypisania. Operator po inkrementacji po prostu zwraca tymczasową kopię obiektu w swoim poprzednim stanie, a ten tymczasowy obiekt (w tym przypadku wskaźnik) może mieć na nim wykonywane operacje.

Teraz, w przypadku:

*data8++ = -*data8; 

bo zamawiania operatora, wskaźnik data8 będzie najpierw po zwiększany, wracając kopię poprzedniej wartości wskaźnika. Ta poprzednia wartość wskaźnika zostanie następnie dereferencjonowana i przypisane wyniki wyrażenia po prawej stronie operatora przypisania.

Edit: Jak inni zwrócili uwagę, jesteś modyfikując zawartość data8 czytając więcej niż raz podczas zapisu do tej lokalizacji pamięci bez punktu sekwencji, tak to jest niezdefiniowane zachowanie.

+0

Jak to jest niezdefiniowane? To tak, jakby twierdzenie, że 'x = -x' jest niezdefiniowane. –

+0

Modyfikujesz zawartość 'data8' (tj. Samą wartość wskaźnika), a następnie czytasz ją z powrotem w dwóch różnych lokalizacjach bez punktu sekwencji. Jak zauważyli inni, otrzymasz dwa różne wyniki, jeśli LHS lub RHS zostaną ocenione jako pierwsze ... czyli "niezdefiniowane zachowanie", ponieważ standard C nie określa, która strona musi być najpierw oceniona ... na przykład oceny LHS i RHS mogą być przeplatane!W twoim przykładzie istnieje wyraźna kolejność oceny, ponieważ LHS nie odczytuje wartości 'x', tylko pisze do niej. Tak więc istnieje tylko jeden odczyt/zapis. – Jason

+0

Tak. Będę pretekstem do braku snu. –

2

++ stosuje się do wskaźnika, a nie do wartości wskazanej przez data8.

*data8++ = -*data8;

odpowiada:

*data8 = -*data8; 
data8++; 

EDIT:
Po przeczytaniu C99 standard 6.5 i Annex C, jasne = nie jest punktem sekwencji. Standard wspomina tylko o wartościach następujących: &&, ||, i ?.

Ponieważ data8 został zmodyfikowany na obu stronach = który ma sensu sekwencji i standard nie określa, czy RHS należy najpierw ocenić Albo LHS należy najpierw ocenić, jestem przekonany, to Undefined Behavior.

Any good reason why assignment operator isn't a sequence point?

Powyższa po omawia = nie będąc punktem sekwencja jest dość podobne tutaj.

+0

'data8' nie jest modyfikowany po obu stronach operatora przypisania, raczej jest modyfikowany na LHS, ale jest czytany dwa razy bez punktu sekwencji określającego, jak odczyty są sekwencjonowane w stosunku do zapisu. – Jason

+0

@Jason masz rację. '=' nie będący punktem sekwencji jest tutaj kluczem. –

7

Jestem prawie pewien, że jest to niezdefiniowane zachowanie.Nie ma sensu sekwencja inna niż ostatecznego średnikiem w:

*data8++ = -*data8; 

Jeśli danych8 jest równa 0x20, to jest równa:

*(0x20) = -*(0x20); 

lub

*(0x20) = -*(0x24); 

Bo tam nie ma sposób podjęcia tej decyzji (ponieważ edytowałeś zmienną podczas jej dwukrotnego czytania, bez punktu sekwencji przeplatania), to jest niezdefiniowane zachowanie niezdefiniowane zachowanie.


Możemy mówić o tym, co robi poniższy fragment kodu. Który prawdopodobnie jest zamierzony przez powyższy kod.

while(data8 != data8End) { 
    *data8 = -*data8; 
    data8++; 
} 

To, co tu robisz, jest, mam nadzieję, bardziej proste. Bierzesz tablicę wejściową i patrzysz na nią, więc jest to seria 8-bitowych liczb. Następnie, w miejscu, negujesz każdy z nich.

+0

Myślę, że mylicie tutaj "zmienne". Wartość wskaźnika i wartość zapisana w jego wskaźniku adresu to dwie różne rzeczy. Nikt w tym przypadku nie edytował zmiennej podczas jej dwukrotnego czytania. Wartość na wskaźniku adresu przez "data8" jest odczytywana raz na RHS. Jest zapisany raz. Wskaźnik zmienia się raz na LHS. –

+0

A może tak. Hehe –

+2

@ Vlad, '=' nie jest punktem sekwencji. –

0

myślę że

* danych8 ++ = - * danych8;

odpowiada

* danych8 = - * (danych8 + 1);

danych8 = danych8 +1

Powiązane problemy