29 Ocak 2016 Cuma

C Veri Tipleri

stdint.h İle Gelen Tipler
C++ ile bu dosya içindeki tipler için specifier'lar sıraya bakılmaksızın kullanılabilir.
3 When multiple simple-type-specifiers are allowed, they can be freely intermixed with other decl-specifiers in any order.
Yani şu tanım doğrudur. long long tipi araya serpiştirilerek tanımlanıyor.
constexpr long static long const int signed x = 10;
C dilinde ise qualifier birden fazla tanımlansa bile sorun olmuyor.
5 If the same qualifier appears more than once in the same specifier-qualifier-list, either directly or via one or more typedefs, the behavior is the same as if it appeared only once....
Yani şu tanım doğrudur. İki defa const yazsak bile sorun olmuyor.
const long const long static const int const signed x = 10;

Sabit Büyüklükte Veri Tipleri
Okumayı kolaylaştırmak için, yazıya önce hep aynı büyüklükte olduğu garanti edilen veri tipleri ile başlamak istedim. Bu tipler stdint.h dosyasında tanımlı. Bu veri tipleri signed olanlar için intN_t unsigned olanlar içinse uintN_t şeklinde tanımlanıyor.

int8_t : genellikle typedef  const signed char int8_t olarak tanımlanır. Bir byte büyüklüğündedir
int16_t:
int32_t:
int64_t : 8 byte büyüklüğündedir. printf yapmak için aşağdaki gibi yapmak gerekir.

Büyüklüğü en az belli bit olması garanti edilen tipler
stdint.h dosyasında int_leastN_t şeklinde tanımlanıyorlar. Örneğin int_least8_t gibi. Bu veri tiplerinin kullanıldığı hiç bir yer görmedim ancak şöyle bir örnek verilebilir. Nadir görülen unsigned int'in 20 bit olduğu bir mimarimiz olsun. Bu mimaride

uint8_t : tanımsızdır.
uint_least8_t : 10 bit'lik char ile aynıdır
uint_fast8_t : muhtemelen unsigned int ile aynıdır.

Eğer bu tür egzotik mimariler ile çalışıyorsak uint_least8_t kullanılabilir.

Büyüklüğü en az belli bit olması garanti edilen tipler. Derleyici en hızlı olanını seçer
stdint.h dosyasında int_fastN_t şeklinde tanımlanıyorlar. Örneğin int_fast8_t gibi. Derleyici en az 8 bitlik bir değer seçer. Eğer 16 bit daha hızlı çalışacaksa 16 bitlik bir değer seçer. (an integral type, which is computed quickly, of at least 8 bits, but it could be 16 bits if they run faster, etc...) Bu veri tiplerinin kullanıldığı hiç bir yer görmedim.

int "most efficient" tiptir. int_fastN_t ise "most efficient type in speed"tiptir.

(7.20.1.3p2) "The typedef name int_fastN_t designates the fastest signed integer type with a width of at least N. The typedef name uint_fastN_t designates the fastest unsigned integer type with a width of at least N."

Dil İle Gelen Tipler

Değişken Büyüklükte Veri Tipleri
C ile gelen veri tipleri platform ve derleyiciye göre değişebiliyor.

Data Type Ranges(C++) sayfasında bazı örnekler var. Ayrıca C Data Types sayfası da faydalı.
Tablo

Type          | Storage size |  Value range
____________________________________________________________
char          | 1 byte       |  -128 to 127 or 0 to 255
unsigned char | 1 byte       |  0 to 255
signed char   | 1 byte       |  -128 to 127
int           | 2 or 4 bytes |  -32,768 to 32,767 or -2,147,483,648 to 2,147,483,647
unsigned int  | 2 or 4 bytes |  0 to 65,535 or 0 to 4,294,967,295
short         | 2 bytes      |  -32,768 to 32,767
unsigned short| 2 bytes      |  0 to 65,535
long          | 4 bytes      |  -2,147,483,648 to 2,147,483,647
unsigned long | 4 bytes      |  0 to 4,294,967,295
Benim anladığım C veri tipleri şu şekilde sınıflandırılabilir:

char başlığı altına düşenler
Bir byte olması gerekiyor. Şu cümle C++ standardından alıntı
sizeof(char), sizeof(signed char) and  sizeof(unsigned char) are 1.
int8_t veya uint8_t aynı şeyler. En büyük ve en küçük değerleri SCHAR_MIN ve SCHAR_MAX macroları ile almak mümkün. SCHAR_MIN -128 SCHAR_MAX ise 127'dir.

Boolean aslında bir bit olması gerektiği halde, işlemci register'ları 1 bit ile çalışmadığı için genellikle bir byte'lık bir veri tipi ile tanımlanır.

short başlığı altına düşenler
short  : en az 2 byte olması gerekiyor, genellikle de zaten 2 byte oluyorlar.

int başlığı altına düşenler
int (unsigned int vs.) : en az 2 byte olması gerekiyor. Ancak genellikle 4 byte oluyorlar. En büyük ve en küçük değerleri INT_MIN ve INT_MAX macroları ile almak mümkün. Unsigned en büyük değeri ise UINT_MAX macrosu ile alabiliriz. Buradaki soruda bir işlemcinin 2 byte'lık int'lere sahip olmasına örnek var.

long başlığı altına düşenler
long (long int, unsigned long vs.) : en az 4 byte olması gerekiyor, genellikle de zaten 4 byte oluyorlar. En büyük ve en küçük değerleri LONG_MIN ve LONG_MAX macroları ile almak mümkün. Unsigned en büyük değeri ise ULONG_MAX macrosu ile alabiliriz.

Not : gcc 32 bit için long'u 4 byte, 64 bit içinse 8 byte olarak tanımlıyor, Windows'ta hep 4 byte uzunluğunda.

long long başlığı altına düşenler
long long (unsigned long long ) : en az 4 byte olması gerekiyor. Genellikle  8 byte oluyorlar.
En büyük ve en küçük değerleri LLONG_MIN ve LLONG_MAX macroları ile almak mümkün. Unsigned en büyük değeri ise ULLONG_MAX macrosu ile alabiliriz.

Sabitleri yazarken aşağıdaki gibi yazmak lazım.
1LL << 40

Eğer sistemde long long tanımlı değilse aşağıdaki gibi tanımlanabilir. upper kısmı en büyük unsigned long ile çarpılarak daha büyük bir sayı elde ediliyor.

typedef struct longlong
{ unsigned long lower; long upper; }
longlong;

#define ToDouble64(ll)    /* Convert to a double.  */    \
    ((ll).upper * 4294967296.0 + (ll).lower)

8 byte'lık veri tipleri eğer unsigned ise 0 ve 18,446,744,073,709,551,615 arasında değer alabiliyor.
8 byte'lık veri tipleri eğer signed ise −9,223,372,036,854,775,808 ve +9,223,372,036,854,775,807 arasında değer alabiliyor.

printf yapmak için %lld veya %llu seçeneğini kullanmak gerekir.

printf("%lld", (long long)now);

Open GL
Eğer OpenGL gibi bir kütüphane ile uğraşıyorsak bazı veri tiplerinin hep aynı büyüklükte olması için kendi veri tipini kullanmak lazım.

GLuint : Her zaman 4 byte


Hiç yorum yok:

Yorum Gönder