2015-09-28 18 views
8

Mam tutaj kilka problemów z bólem głowy.Kiedy int nie jest int (intX_t)

Zasadniczo staram się, aby biblioteka była kompatybilna z różnymi systemami Arduino (a nie z Arduino).

Mam sytuację, w której typy już nie pasują, tak jak w przypadku int nie jest już równoznaczny z identycznym typem stałej szerokości. W ograniczonym środowisku (bez stdlib i innych) napisałem własne klasy cech dla potrzebnych mi funkcji.

Wszystko działa poprawnie, używając GCC 4.8.1 (avr) & Extensa-1x106-GCC (ESP8266), ale nie w GCC 4.8.3 (SAM, SAMD rdzenie).

Zasadniczo mam knuckled dół mojego kodu, aby pokazać ten problem w ten kod bardzo podstawowego (int potwierdza mieć 4 bajty na uszkodzonej kompilatorów platformy 32-bitowy):

template < typename T, typename U > struct is_same{ enum { value = false }; }; 
template < typename T > struct is_same< T, T > { enum { value = true }; }; 

void setup() { 
    static_assert(is_same<int,int32_t>::value, "Not integer"); 
} 

void loop(){} 

można wyświetlić " normalna implementacja C++ tutaj (powyżej to podstawowa implementacja do użycia w Arduino IDE): http://cpp.sh/377e

Nawiasem mówiąc, aser statyczny nie uruchamia się również w kompilatorze cpp.sh.

Czy 4.8.1 niepoprawny, czyli int i int32_t należy traktować jako różne typy. Lub jest 4.8.3 niepoprawne i powinny być równoważne, jeśli mają równe rozmiary określone przez implementację.

Użyłem poniższego kodu do wykrycia dowolnego typu liczby całkowitej, w której początkowo znajdowałem błąd.

template< typename T > 
    struct is_integer{ 
     enum{ 
      V8 = is_same< T, uint8_t >::value || is_same< T, int8_t >::value, 
      V16 = is_same< T, uint16_t >::value || is_same< T, int16_t >::value, 
      V32 = is_same< T, uint32_t >::value || is_same< T, int32_t >::value, 
      V64 = is_same< T, uint64_t >::value || is_same< T, int64_t >::value, 
      value = V8 || V16 || V32 || V64 
     }; 
}; 

I oczywiście może się zmienić, aby sprawdzić char, int, long, etc .. ale nadal będzie ona wymagać sprawdzania wszystkich stałych wariantach szerokości i najprawdopodobniej int_fastX_t i int_leastX_t rodzajów, które wydaje się super nadmiarowa metoda zapewniająca maksymalną użyteczność.

Wszelkie pomysły?

Pozdrawiam, doceniam wszelkie dane wejściowe!

+1

Czy dany toolchain jest dostępny gdzieś? – melak47

+0

możesz użyć [boost] (http://www.boost.org/doc/libs/1_59_0/libs/integer/doc/html/boost_integer/traits.html) w swoim środowisku osadzonym? –

+0

@ melak47 Tak, możesz pobrać [Arduino IDE] (https://www.arduino.cc/en/Main/Software) i z menu Narzędzia-> Zarząd-> Zarządca wybierz i zainstaluj SAM, lub Rdzeń SAMD dla jednej z niedziałających sieci (wykona resztę), następnie wybierz Zero (SAMD) lub Due (SAM) z listy Narzędzia-> Tablica. (To jest ból, ale przeznaczony dla początkujących). Rdzeń AVR 4.8.1 jest dostarczany domyślnie. –

Odpowiedz

4

Jest to zależne od standardu C; C++ po prostu dziedziczy zachowanie przez jawne odniesienie.

Co mówi średnia C:

  • Jeśli int32_t jest zdefiniowana, to odnosi się do podpisanego 32-bit 2 jest dopełniacza liczby całkowitej.

  • Jeśli implementacja zapewnia podpisany 32-bitowy typ liczbowy dopełnienia 2, musi podać typedef int32_t, który się do niego odwoła.

Nowhere to powiedzieć, że ten 32-bit 2 jest uzupełnieniem podpisana liczba całkowita typ musi być int.Z technicznego punktu widzenia, nawet jeśli jest liczbą całkowitą całkowitą dopełniacza 2, jest całkowicie możliwe, że implementacja zapewnia również wyraźny 32-bitowy dopełniacz typu integer ze znakiem i definiuje int32_t, aby odnosić się do tego innego typu.

Obawiam się, że jedynym w pełni ogólnym rozwiązaniem byłoby wylistowanie wszystkich podstawowych typów, typów o stałej szerokości, typów o minimalnej szerokości i typów o minimalnej szerokości.

Aby coś mniej zniechęcającego, powinno być możliwe sprawdzenie dokumentacji narzędzi, które chcesz wspierać, aby dowiedzieć się, jakie typy zapewniają i jak je nazywają. Jeśli ten zestaw "toolchains, które chcesz wspierać" jest nieograniczony, nie sądzę, że istnieje łatwiejsze wyjście.

+1

Możesz uczynić to nieco mniej szalonym, tworząc szablon cech, który zapewnia szybką, stałą szerokość, min szerokości, szybką min-szerokość dla danego rozmiaru i sygnatury. To przynajmniej dzieli listy na łatwe do opanowania części. Wrzuć listy typów wszystkich podstawowych typów (i sygnatury) plus size_t i inne podobne integralne typy niezdefiniowanej opatrzności, a następnie niektóre metaprogramowanie, aby działać na wszystkich z nich jednolicie ... – Yakk

+0

Lista wszystkich typów zdecydowanie obejmowałaby to wszystko, jednak we wszystkich testowanych kompilatorach (4 różne architektury) zastąpienie stałych liczb całkowitych całkowitymi typami podstawowymi okazało się w moim przypadku dobre. Może wymagać aktualizacji w przyszłości, ale większość zastosowań obejmie liczbę całkowitą. Przyjęta odpowiedź. –

0

Z C11 standardowej 7.20.1.1 (1)

Nazwa typedef intN_t oznacza podpisaną typu całkowitą o szerokości N, NO wypełniających bitów, i dwie w reprezentacji dopełniacza. Zatem int8_t oznacza taki podpisany typ liczby całkowitej o szerokości dokładnie 8 bitów.

Tak więc int32_t to liczba całkowita ze znakiem, która ma dokładnie 32 bity szerokości.

int że określa się jako sizeof(int) jest większa niż lub równa char (C++ 14 3.9.1 (2)) oraz, że podpisany Int musi reprezentować [-32767, 32767] (C11 5.2.4.2.1) . Ten zakres wynosi w rzeczywistości 16 bitów.

Tak więc nigdy nie może być równoznaczne z intN_t jako intN_t może być zdefiniowanym w implementacji typem oddzielonym od standardowego typu.

+0

Szerokość zaimplementowanej 'int' nie ma znaczenia, porównuję ją ze wszystkimi wariantami o stałej szerokości. Żadne nie pasują. –

Powiązane problemy