21 Mayıs 2020 Perşembe

sizeof

sizeof
Belirtilen tipin ne kadar bellek alanı tuttuğunu döner.

sizeof aslında bir operator olarak görülür
Açıklaması şöyle
The sizeof is an operator, not a function, and as any operator it has a precedence, which is in C lower than of the ++ operator. Therefore the construct sizeof(a)++ is equivalent to sizeof a++ which is in turn equivalent to sizeof (a++). Here we have postincrement on a which is an lvalue so it is perfectly legal. If instead of a you have 3 which is not lvalue, the compilation will fail.
Örnek
Elimizde şöyle bir kod olsun. Bu kod önce 3++ yapmaya çalıştığı için hata verir.
printf("%d", sizeof(3)++);
Örnek - operator'ler arasında öncelik
Açıklaması şöyle.
[] have a higher precendence than sizeof. So sizeof(my_arr)[0] is the same as sizeof((my_arr)[0]).
Şöyle yaparız. Dolayısla sizeof(my_arr)[0] şeklinde de yazsaydık parantezlerin etkisi olmayacaktı önce [0] işletilecekti.
uint32_t my_arr[2];
sizeof my_arr[0] == 4;
Şöyle yaparız
Static uint32_t my_arr[2];
_Static_assert(sizeof(my_arr) == 8, "");
_Static_assert(sizeof(my_arr[0]) == 4, "");
_Static_assert(sizeof(my_arr)[0] == 4, "");
sizeof parantez ile kullanıır
Yoksa şu gibi örnekler farklı farklı algılanabilir
sizeof char * + 3
C ve C++ Farklı Çalışabilir.
C ve C++ dillerinin ayrıldığı ender noktalardan birisi sizeof.

1. C dilinde karakterler otomatik olarak int'e cast edilir. Dolayısıyla çıktı olarak 1 ve 4 alırız. C++ ise çıktı olarak 1 ve 1 döner.
char c = 'A';
printf("%d\n",sizeof(c));// output = 1
printf("%d\n",sizeof('A')); // output = 4
2. C dilinde sizeof runtime sırasında çalıştırılabilir.
Açıklaması şöyle.
If the type of expression is a variable-length array type, expression is evaluated and the size of the array it evaluates to is calculated at run time.
Örnek
Şöyle yaparız.
#include <stdio.h>

int main() {
  int i=1, j=1;
  int a[i][j];
  int b[1][1];

  (void) sizeof(a[--i]); //i is decreased
  (void) sizeof(b[--j]);
  printf("%d %d", i, j);

  return 0;
}
C++ sizeof derleme sırasında çalıştırılır
Açıklaması şöyle
If the type of the operand is a variable length array type, the operand is evaluated; otherwise,the operand is not evaluated and the result is an integer constant.
Aşağıdaki kodda n'in değeri artmaz.
int n = 100;
int size_int = sizeof(++n);
std::cout<<n;
Sebebi ise sizeof()'un n'in değerine değil, tipine bakarak kod üretmesidir. Üretilen assembly kodu, aşağıdaki gibi bir sabit - yani 4 - kullanır.
mov dword ptr [size_int],4
sizeof derleme esnasında çalıştığı için null_ptr sorunu da olmaz. Elimizde şöyle bir kod olsun.
char **p = NULL;
printf("%d,%d\n", sizeof(*p), sizeof(**p));
Çıktı olarak şunu alırız. İlk sizeof char* olduğu için 64 bit sistemde 8 byte uzunluğundadır. İkinci sizeof ise char olduğu için 1 byte uzunluğundadır.
8,1
sizeof sadece char tipi için garanti verir
char tipi mutlaka 1 byte olmalıdır. Geri kalan tipler ve sınıflar için bir garanti verilmez.

sizeof array için sizeof(T)*n şeklinde çalışır
Açıklaması şöyle.
When sizeof is applied .... to an operand that has array type, the result is the total number of bytes in the array. When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding.
iki pointer tipi için sizeof farklı değer dönebilir.
Eski mimariler için böyle bir kural getirilmiş. Artık yeni donanım mimarileri için geçerli değil.
An int* could still be implemented as a single hardware pointer, since C++ allows sizeof(char*) != sizeof(int*).
empty base optimization - sizeof mutlaka bir 0'dan büyük bir değer döner
C dili boş sınıf tanımlanmasına izin vermez.
If the struct-declaration-list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined.
C++ ise izin verir. Bazı sınıflar hiç member variable tanımlamasa bile en az 1 byte yer tutarlar. Böylece bu tür sınıflar array olarak kullanılabiliyorlar. Açıklaması şöyle
G++ treats empty structures as if they had a single member of type char.
Örnek
Elimizde şöyle bir kod olsun
class A
{
public:
  bool operator()(int x) const
  {
    return x>0;
  }
};

A a;
std::cout << "sizeof(A)=" << sizeof(A);
Sonuç olarak 1 alırız. Sebebi ise bir C++ kuralı.
"All complete objects must have a unique address; so they must take up at least one byte of storage - the byte at their address."
Örnek
Elimizde şöyle bir kod olsun.
struct base {};
struct child : base {};
Şöyle yaparız ve çıktı olarak 1 alırız.
sizeof(child)
empty base optimization ne zaman olmaz
Açıklaması şöyle
Empty base optimization is prohibited if one of the empty base classes is also the type or the base of the type of the first non-static data member
Elimizde şöyle bir kod olsun.
struct base {};
struct child : base {base b;};
Şöyle yaparız ve çıktı olarak >=2 alırız.
sizeof(child)
empty base optimization STL İçinde Kullanılır
Açıklaması şöyle. Eski STL kodlarında empty base optimization için allocator'dan kalıtılır.
Allocator-aware containers are required to store the value of an allocator that the user provides (which defaults to a default-constructed allocator of that type). That means the container must have a subobject of that type, which is initialized by the allocator value the user provides. And that subobject takes up space... in theory.

Consider std::vector. The common implementation of this type is to use 3 pointers: one for the beginning of the array, one for the end of the useful part of the array, and one for the end of the allocated block for the array. In a 64-bit compilation, these 3 pointers require 24 bytes of storage.

A stateless allocator doesn't actually have any data to store. But in C++, every object has a size of at least 1. So if vector stored an allocator as a member, every vector<T, Alloc> would have to take up at least 32 bytes, even if the allocator stores nothing.

The common workaround to this is to derive vector<T, Alloc> from Alloc itself. The reason being that base class subobject are not required to have a size of 1. If a base class has no members and has no non-empty base classes, then the compiler is permitted to optimize the size of the base class within the derived class to not actually take up space. This is called the "empty base optimization" (and it's required for standard layout types).

So if you provide a stateless allocator, a vector<T, Alloc> implementation that inherits from this allocator type is still just 24 bytes in size.

But there's a problem: you have to inherit from the allocator. And that's really annoying. And dangerous. First, the allocator could be final, which is in fact allowed by the standard. Second, the allocator could have members that interfere with the vector's members. Third, it's an idiom that people have to learn, which makes it folk wisdom among C++ programmers, rather than an obvious tool for any of them to use.

İstisnai Durum - zero length array
Açıklaması şöyle
Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure that is really a header for a variable-length object.
gcc zero length array içeren struct tanımlanmasına izin veriyor. Bu bir extension ve standart değil. Elimizde şöyle bir kod olsun
struct EmptyStruct
{
};

struct StructEmptyArr
{
    int arr[0];
};

printf("sizeof(EmptyStruct) = %ld\n", sizeof(EmptyStruct));
printf("sizeof(StructEmptyArr) = %ld\n", sizeof(StructEmptyArr));
Çıktı olarak şunu alırız.
sizeof(EmptyStruct) = 1
sizeof(StructEmptyArr) = 0
const ve const olmayan tip arasında fark yoktur
sizeof(T*) != sizeof(const T*)
bu iki çağrı her zaman birbirine eşittir. Farklı bir sayı döndükleri durum yoktur.

sizeof ve kalıtım
A ve ondan kalıtan B sınıfı olsun.
class A {
  int member1; 
public:
  char member2;
};

class B : public A 
{
  int member3;
public:
  float member4;
};
Mantıken B sınıfının daha fazla yer tutması beklenir, ancak sizeof derleyiciye mahsus olduğu için ne kadar daha fazla yer tutacağını bilemeyiz. Sınıfın alanının public, protected olması fark yaratmaz.

sizeof function için uygulanamaz
Açıklaması şöyle
The sizeof operator shall not be applied to an expression that has function or incomplete type
Şu kod void() bir function tanımlaması olduğu için yanlıştır.
std::cout << "size of function: " << sizeof(void()) << '\n'; // error


Hiç yorum yok:

Yorum Gönder