2017-02-11 22 views
5

Na przykład, jest następująca funkcja prawna:Czy legalne jest używanie memcpy ze strukturą docelową ze stałymi członkami?

struct two_int { 
    const int a, b; 
} 

void copy_two(const two_int *src, two_int *dest) { 
    memcpy(dest, src, sizeof(two_int)); 
} 

Wydaje się, że przynajmniej niektórerodzaje modyfikacji wartości stałych definiowane jest niedozwolone, ale to nie jest dla mnie jasne, czy to kwalifikuje.

Jeśli odpowiedź brzmi „nie jest dozwolone, w ogóle”, ja też zastanawiać szczególnym przypadku, gdzie dest jest nowo przydzielonego pamięć malloc (a więc jeszcze nie przypisano żadnej wartości), takich jak:

two_int s = {.a = 1, .b = 2}; 
two_int *d = malloc(sizeof(two_int)); 
copy_two(&s, d); 

Aktualizacja: wydaje się, że ta ostatnia kwestia wydaje się odpowiedzieć twierdząco (jest OK) w przypadku nowo malloc „struktury d, ale oryginalne, bardziej ogólne pytanie nadal stoi , Myślę.

+4

Nr Próba modyfikacji zmiennych stałych * w dowolnym miejscu * jest * niezdefiniowanym zachowaniem *. –

+2

Oznacza to, że 'two_int' może _never_ zostać przydzielone przez' malloc' lub inaczej dynamicznie, prawda? Ponieważ nie można przekazać żadnych informacji konstrukcyjnych do 'malloc' ... – SODIMM

+1

To pytanie może kwalifikować się do znacznika [language-lawyer]. –

Odpowiedz

0

Używanie do tego celu miałoby zdefiniowane zachowanie tylko wtedy, gdy rzeczywisty obiekt docelowy nie ma stałego lub automatycznego czasu trwania.

względu na kod:

struct foo { double const x; }; 
void outsideFunction(struct foo *p); 

double test(void) 
{ 
    struct foo s1 = {0.12345678}; 
    outsideFunction(&s1); 
    return 0.12345678; 
} 

kompilator byłby uprawniony do optymalizacji funkcji do:

double test(void) 
{ 
    static struct foo const s1 = {0.12345678}; 
    outsideFunction(&s1); 
    return s1.x; 
} 

na wielu procesorach, jedynym sposobem, aby załadować podwójne z dowolną stałą jest wczytaj jego wartość z obiektu trzymającego stałą, iw tym przypadku kompilator mógłby wygodnie znać obiekt (s1.x), który musi utrzymywać stałą 0.12345678. Efektem sieci byłoby, że kod, który użyłby memcpy do napisania na s1.x mógłby uszkodzić inne zastosowania stałej liczbowej 0.12345678. Jak to się mówi, "zmienne nie będą, a stałe nie". Paskudne rzeczy.

Problem nie istnieje dla obiektów o przydzielonym czasie trwania, ponieważ memcpy wymaga, aby kompilator "zapomniał" o wszystkich przechowywanych w pamięci docelowej, w tym o "typie efektywnym". Zadeklarowane rodzaje obiektów statycznych i automatycznych istnieją niezależnie od wszystkiego, co jest w nich przechowywane, i nie można ich usunąć za pomocą "memcpy" ani żadnych innych środków, ale obiekty o przydzielonym czasie trwania mają tylko "efektywny typ", który zostałby usunięty.

+0

To jest ważny przykład, ale czy nie jest to specjalny przypadek ogólnego problemu? Jeśli wykluczysz struktury, które składają się tylko z członków const, to czy będzie możliwe ich kopiowanie? – jxh

+0

@jxh: Zacząłem od bardziej skomplikowanego przykładu, który w tym przypadku się nie udał. Załóżmy, że 'struct foo' ma niestałych członków, ale funkcja wzięła argument' v', zainicjował 's1.x' na' v + 0.12345678', a następnie zwrócił 'v + 0.12345678'. Kompilator będzie miał prawo zauważyć, że wartość w 's1.x' dokładnie dopasowała to, co było potrzebne do zwrócenia, a tym samym załadować tę wartość. Mogłem zobaczyć użyteczność posiadania silniejszej formy "const", która obiecałaby, że jeśli kod odczyta wartość obiektu, wszelkie późniejsze odczyty tego obiektu * za pomocą wskaźnika, który został wyprowadzony ... – supercat

+0

... z adresu tego obiektu bez Konwersje dowolnego typu * przyniosłyby tę samą wartość, ale wymagałoby to rozpoznania, że ​​konwersje typów powinny wpłynąć na założenia kompilatora dotyczące celu wskaźnika. Sądzę, że to oczywiste, że powinni, ale projektowanie kompilatorów takich jak GCC byłoby trudne. – supercat

Powiązane problemy