2013-01-07 12 views
20

Który z liter C powinien być użyty do przedstawienia różnicy między rozmiarami dwóch obiektów?Jaki typ odjąć 2 size_t's?

Jak size_t jest niepodpisany, coś

size_t diff = sizeof (small_struct) - sizeof (big_struct); 

oczywiście nie byłoby poprawne i wydaje mi się, że nie ma rzeczywistego podpisane równoważne.

ptrdiff_t brzmi rodzaju kuszące, ale

  1. jak jego nazwa mówi, że to za odjęcie wskazówek.
  2. Przeczytałem to np. Segmentowane platformy, takie jak DOS, mają maksymalny rozmiar obiektu 64 tys., który można przedstawić za pomocą 16-bitów. Dalekie wskaźniki są jednak złożone z 16-bitowej wartości segmentu i 16-bitowej wartości offsetu. Czy to nie sprawiłoby, że ptrdiff_t również na takiej platformie 32-bitowej? Jeśli tak, różnica między dwoma obiektami wymagała tylko 16-bitowego rozmiaru, ale użycie ptrdiff_t dałoby 32-bitową zmienną szeroką, co czyni ją nieoptymalną.

Jaki jest zatem odpowiedni przenośny typ do pracy z taką wartością?

Edit: wiem o ssize_t, ale to

  1. nie jest częścią standardowej C.
  2. faktycznie nie są przeznaczone do takiego użytku, ale o powrocie bądź wielkość lub (ujemne) wartości błędu.
+0

'ssize_t' jest podpisany' size_t' –

+1

@AFAIK 'ssize_t' jest POSIX, nie ISO C. –

+2

@RomanR. 'ssize_t' nie jest C Standardem i nie ma gwarancji, że wartość' size_t' zmieści się w 'ssize_t' w POSIX. – ouah

Odpowiedz

8

Nie ma standardowego typu danych, który gwarantuje 100% bezpieczeństwa dla tego, co próbujesz zrobić. Aby uzyskać dowód, wyobraź sobie, że jeśli size_t jest naprawdę tylko size_t, jest to całkowicie możliwe. Wtedy nie ma standardowego typu danych C, który gwarantuje, że ma dodatni zakres, który pasuje do uint64_t, a także obsługuje wartości ujemne.

Tak więc prostą odpowiedzią na twoje pytanie jest "brak typu danych" (przy założeniu ścisłego przestrzegania standardowego C, co wydaje się być pożądane).

Nie masz jasności co do sposobu użycia i możliwe, że będziesz w stanie wykorzystać modułową arytmetykę do obsługi wartości "ujemnych". Na przykład, the following code skutkuje d2 będąc 4 powodu modułowej arytmetyki, dzięki czemu kod działać jakby size_t zostały podpisane:

#include <stdio.h> 
#include <stdint.h> 

int main() 
{ 
    size_t d1 = sizeof(int32_t) - sizeof(int64_t); 
    size_t d2 = sizeof(int64_t) + d1; // Add difference (even if d1 is "negative"*) 

    printf("d1: %zu\n", d1); 
    printf("d2: %zu\n", d2); 

    return 0; 
    // * By "negative" I mean that d1 would be negative if size_t were signed 
} 

Modular arytmetyka może nie wystarczyć dla Ciebie w Twoim przypadku, ale dla innych może ona.

18

Kiedy jestem naprawdę martwi się o kwestie przelewowych, jak to (szczególnie podczas pracy w modułowej arytmetyki gdzie „negatywne” wartości owinąć gdzieś indziej niż ~0) Ja po prostu podzielić go na dwa przypadki:

if (a > b) { 
    size_t diff = a - b; 
} else { 
    size_t diff = b - a; 
    // code here subtracts diff rather than adds it, etc. 
} 
2

Nie nie jest podpisaną liczbą całkowitą typu C, która może zawierać wszystkie wartości z wartości size_t.

+2

W swojej implementacji? Czy jest to zabronione przez Standard? :) – pmg

+0

Miałem na myśli we wszystkich realizacjach. Istnieją oczywiście implementacje, w których wszystkie wartości 'size_t' mogą zmieścić się w typie liczby ze znakiem. – ouah

-2

Można to zrobić:

size_t diff = std::abs(static_cast <int> (sizeof (small_struct) - sizeof (big_struct)));