Zawiły kod - jak działa?

0

Dobry wieczór, mam pytanie odnośnie kodu zamieszczonego poniżej. Czy dobrze rozumiem, że począwszy od obiektu s zawartość struktury m jest kopiowana, bajt po bajcie, w miejsce wskazywane przez wskaźnik tp?

typedef struct {
	int a;
	short s[2];
} MSG;

MSG *mp, m = {4, {1, 0}};

char *fp, *tp;

mp = (MSG *) malloc(sizeof(MSG));

for (fp = (char *)m.s, tp = (char *)mp->s; tp < (char *)(mp+1);)
	*tp++ = *fp++;
2

kod pętli robi to samo co

mp->s[0] = m.s[0];
mp->s[1] = m.s[1];
1

Wywal go i napisz po ludzku:

typedef struct
  {
   int a;
   short s[2];
  }MSG;
MSG *mp;
mp=(MSG*)malloc(sizeof(MSG));
mp->s[0]=1;
mp->s[1]=0;
0

Dziękuję za odpowiedzi. Ten kod jest z książki i chyba celowo jest tak napisany. Jeszcze jedno pytanie. Jeżeli jest wskaźnik typu char na liczbę typu short int, to np. takie wywołanie printf jak poniżej:

typedef struct {
	int a;
	short s[2];
} MSG;

MSG *mp, m = {4, 1, 0};
char *fp, *tp;
mp = (MSG *) malloc(sizeof(MSG));

fp = (char *)m.s;

printf("val = %d\n", *fp++);
printf("val = %d\n", *fp++); 

Pierwszy printf zinterpretuje pierwsze 8 bitów s[0] jako jedną liczbę w U2 i ją wypisze, a drugie wywołanie zrobi to samo dla kolejnych 8 bitów?

0

Weź wstaw do kompilatora i sprawdź co to zrobi.

0

No tak mi wychodzi właśnie. Chciałem się tylko upewnić.

2

jako jedną liczbę w U2

Według standardu, char ma nieokreśloną „znakowość” i może być ze znakiem albo bez znaku, zależnie od kompilatora.
Jeśli chcesz 8-bitową liczbę ze znakiem to jest signed char, a bez znaku unsigned char.

Poza tym, żeby ci nie przyszło do głowy robić tego samego ze wskaźnikami innego typu (nie char/unsigned char).
Nie można np. robić czegoś takiego:

int x = 424242424;
short *s = &x;
printf("%d", *s);

czy to ci wyświetli shorta jako pierwsze dwa bajty inta? (zakładając że sizeof(int)==4 && sizeof(short)==2)?
NIE! a dlaczego, to poczytaj o strict aliasing.

0

Jeżeli nie mam gdzieś błędu, to kod poniżej właśnie tak działa. Czy coś poplątałem?

(0001 1001 0100 1001 | 0110 1100 1111 1000)_2 = (424242424)_10

http://ideone.com/USWllJ

#include <stdlib.h>
#include <stdio.h>

int main(void){

        int x = 424242424;
        unsigned short *s = (unsigned short *)&x;

        printf("sizeof(int) = %lu\n",
                sizeof(int));
        printf("sizeof(unsigned short) = %lu\n",
                sizeof(unsigned short));

        printf("%d\n", *s++); // (0110 1100 1111 1000)_2 = (27896)_10
        printf("%d\n", *s++); // (0001 1001 0100 1001)_2 = (6473)_10

        return 0;
}
1

Poplątałeś to, że jest to undefined behaviour. Dzisiaj działa, a jutro może nie działać, bo zmieni się wersja kompilatora albo włączysz optymalizację.
http://dbp-consulting.com/StrictAliasing.pdf

Przykładowo, w przypadku takiej funkcji:

int foo()
{
    int x = 424242424;
    short *s = &x;
    *s = 0;
    return x;
}

kompilator ma prawo zamienić ostatnie return x; na return 424242424; bo widzi że wartość x się nie zmienia — mimo że faktycznie zmieniasz wartość x w linijce *s = 0.
Jednak tego nie wolno robić — konkretnie nie wolno dereferować wskaźnika innego typu niż wskazywana przezeń zmienna, czyli *s = jest błędem, który się co prawda kompiluje, ale nie musi poprawnie działać.

Program może ci wyświetlić 424214528, może 424242424, może -1, a może wysłać twoje nagie fotki na Facebooka ;-)

0

Nie wiedziałem o tym. :( Dziękuję za informację i wytłumaczenie. A propos tego podlinkowanego artykułu, to dobrze rozumiem, że ten cały strict-aliasing jest przede wszystkim (a nawet wyłącznie) dla wygody ludzi, którzy piszą kompilatory?

1

To jest okazja do optymalizacji kodu – aby program ogólne szybciej działał. Kompilator może z tego korzystać, ale nie musi. Jeśli korzysta, to jest lepszym kompilatorem (generuje szybciej działający kod). Trudno to nazwać wygodą ludzi piszących kompilatory, skoro mają dzięki temu więcej pracy. Mogliby przecież olać temat zupełnie...

Z punktu widzenia programisty C czy C++ trzeba pamiętać, że nie wolno wyczarowywać sobie zmiennych, których tam nie ma.

1 użytkowników online, w tym zalogowanych: 0, gości: 1