# C Lua: Functions

- **İngilizce aslı:** https://wiki.facepunch.com/gmod/C_Lua:_Functions
- **Çeviri tarihi:** 2025-09-08

## Kaynaklar

İkili modüller oluşturmak için IDE'nizi henüz kurmadıysanız, aşağıdaki sayfalardan birine bakın:

- [İkili Modüller Oluşturma: Premake](https://gmod.tr/wiki/Creating_Binary_Modules:_Premake) (Önerilir)
- [İkili Modüller Oluşturma: CMake](https://gmod.tr/wiki/Creating_Binary_Modules:_CMake)
- [İkili Modüller Yapmak İçin Visual Studio'yu Ayarlama](https://gmod.tr/wiki/Setting_Visual_Studio_Up_for_Making_Binary_Modules) (Kullanımdan Kaldırıldı)

Daha önce hiç C++ kullanmadıysanız, temel bilgileri edinmenize yardımcı olacak [bir eğitim mevcuttur](http://www.cplusplus.com).

[Lua C API Dokümantasyonu](https://www.lua.org/manual/5.1/manual.html#3), Lua'nın C API'sini anlamak için son derece faydalı bir kaynaktır.

Ek faydalı fonksiyonlar için [LuaBase.h](https://github.com/Facepunch/gmod-module-base/blob/development/include/GarrysMod/Lua/LuaBase.h) dosyasına başvurabilirsiniz.

## Gezinme

Bu, daha kolay gezinmenizi sağlamak için bu sayfadaki tüm bölümleri içeren bir listedir.

- [Yığınları (stack) anlama](https://gmod.tr/wiki/C_Lua:_Functions#understandingstacks)
- [Lua için C++ fonksiyonları oluşturma](https://gmod.tr/wiki/C_Lua:_Functions#creatingcfunctionsforlua)
- [C++ İçinde Lua Fonksiyonu Çağırma](https://gmod.tr/wiki/C_Lua:_Functions#callingluafunctioninc)
- [Bir Lua Tablosu Üzerinde Yineleme.](https://gmod.tr/wiki/C_Lua:_Functions#iteratingoveraluatable)
- [Okunabilirlik ve kolaylık için C++ fonksiyonları oluşturma](https://gmod.tr/wiki/C_Lua:_Functions#creatingcfunctionsforreadabilityconvenience)
- [Userdata ve metatablolar hakkında bir not](https://gmod.tr/wiki/C_Lua:_Functions#anoteonuserdatametatables)

## Yığınları (stack) anlama

Lua'nın C API'si yığınlar (stack) üzerine kuruludur ve bunları anlamak kritik öneme sahiptir.

Yığın, kendisine elemanların "pushed" (itilebildiği) ve ondan "popped" (çekilebildiği) bir tür dizidir.

Bir elemanı itmek (pushing) onu yığının en üstüne koyarken, yığından çekmek (popping) en üstteki elemanı kaldırır.

Yığınların kısıtlayıcı doğasını atlayarak, yığındaki belirli konumlara değer eklemek ve kaldırmak için `Remove` ve `Insert` fonksiyonlarını kullanmak da mümkündür, ancak bunları idareli kullanmalısınız.

Yığın konumlarını alırken sık sık negatif sayılar göreceksiniz. `1` yığının en altını veya ilk elemanı ifade ederken, `-1` yığının en üstünü veya son/en yeni elemanı ifade eder. `-1` genellikle yığının en üstüne yeni itilmiş değeri almak için kullanılır. `-2` en üstten ikinci veya sondan ikinci değeri alır.

**Lua'nın C API'sindeki belirli fonksiyonların yığınla potansiyel olarak beklenmedik şekillerde etkileşime girdiğini ve hatalarla karşılaşıp yığının takibini kaybederseniz, kullandığınız fonksiyonları araştırmanız gerektiğini unutmamak önemlidir.**

Güçlü bir örnek `Call` fonksiyonudur. C API'sinden bir fonksiyonu çağırmak, fonksiyonu ve her argümanı yığından çeker (pop).

Aşağıdaki kod parçacığı `math.floor(5.6)` fonksiyonunu çağırır ve geri dönüş değerini bir `double MyDouble` içinde saklarken, mevcut yığının bir görselleştirmesini tanıdık bir dizi formatında yorum olarak gösterir:

```lua
double MyDouble;
// Global tabloyu al, [Global{}]
LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB);
	// math tablosunu al, [Global{}, math{}]
	LUA->GetField(-1, "math");
	// floor fonksiyonunu al, [Global{}, math{}, floor()]
	LUA->GetField(-1, "floor");
	// double 5.6'yı it, [Global{}, math{}, floor(), 5.6]
	LUA->PushNumber(5.6);
	// 1 argümanlı ve 1 geri dönüş değerli bir fonksiyon çağır
	// Bu, floor() fonksiyonunu ve 5.6 argümanını yığından çeker (pop), ardından geri dönüş değerini yığının en üstüne iter (push)
	// Yığın şimdi [Global{}, math{}, 5]
	LUA->Call(1, 1);
	// Yığının en üstündeki sayıyı alır, ÇEKMEZ (POP ETMEZ), ve MyDouble içinde saklar, [Global{}, math{}, 5]
	MyDouble = LUA->GetNumber(-1);
// Global{}, math{} ve 5'i yığından çeker (pop), []
LUA->Pop(3);
```

## Lua için C++ fonksiyonları oluşturma

Lua için C++ fonksiyonları yapmak, ikili dosyalarınız (binary) için kesinlikle gereklidir. Bu olmadan, modülleriniz o kadar da kullanışlı olmaz. Bu bölümde, Lua'da kullanılmak üzere C++'da fonksiyonlar oluşturmayı, argümanları kontrol etmeyi ve değerleri döndürmeyi ele alacağım.

### Fonksiyonumuzu C++'da Tanımlama

Yapacağımız ilk şey C++ fonksiyonumuzu tanımlamaktır.

```lua
LUA_FUNCTION( MyFirstFunction )
 {
     //Buraya birazdan bir şeyler ekleyeceğiz
 }
```

Şimdi boş bir fonksiyonumuz olduğuna göre, bir değer döndürmesini sağlayalım. Bunu yapmak için yığına bir şey iteriz ve ardından döndürmek istediğimiz değer sayısını geri döndürürüz. Yani bu durumda bir bool, true, iteceğiz ve sonra 1 döndüreceğiz.

```lua
LUA_FUNCTION( MyFirstFunction )
 {
     LUA->PushBool( true ); // bool değerimizi yığına it.

     return 1; // Kaç değer döndürdüğümüz
 }
```

Şimdi bu fonksiyonu Lua'da çağırsaydık, ki henüz yapamayız çünkü sadece C++'da tanımladık, o zaman her zaman true döndürürdü.

Pekala, şimdi nasıl çalıştığına dair temel bir anlayışa sahip olduğunuza göre, onu daha karmaşık hale getirelim. Bir parametre ekleyelim ve belirli bir değerin üzerindeyse true, aksi takdirde false döndürelim.

```lua
LUA_FUNCTION( MyFirstFunction )
 {
     LUA->CheckType( 1, GarrysMod::Lua::Type::Number ); // İlk argümanın bir sayı olduğundan emin ol

     double number = (LUA->GetNumber( 1 )); // İlk argümanı al

     if (number > 9.0) // Eğer sayı 9'dan büyükse...
     {
         LUA->PushBool( true ); // true it...
     }
     else
     {
         LUA->PushBool( false ); // değilse, false it.
     }

     return 1; // Kaç değer döndürdüğümüz
 }
```

### C++ Fonksiyonumuzu Lua'da Tanımlama

Şimdi fonksiyonumuzu oluşturduğumuza göre, onu Lua'da çağırmanın bir yoluna ihtiyacımız var. Bu kolay kısım.

```lua
GMOD_MODULE_OPEN()
 {
     LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Global tabloyu it
          LUA->PushCFunction( MyFirstFunction ); // Fonksiyonumuzu it
          LUA->SetField( -2, "MyFirstFunction" ); // Lua'daki MyFirstFunction'ı bizim C++ fonksiyonumuza ayarla
     LUA->Pop(); // Global tabloyu yığından çek

     return 0;
 }
```

Bu, Lua'daki "MyFirstFunction" değişkenini C++'daki "MyFirstFunction" fonksiyonuna ayarlar, böylece Lua'da şu şekilde çağırabilirsiniz:

```lua
MyFirstFunction( <number> )
```

## C++ İçinde Lua Fonksiyonu Çağırma

Lua C kullanarak Lua fonksiyonlarını nasıl çağıracağınızı bilmek çok faydalıdır. Bu bölümde, fonksiyonları çağırmayı ve geri dönüş değerlerini almayı ele alacağım. Şimdi Call'un nasıl çalıştığına dair kısa bir açıklama. Aşağıdakini yapsaydım:

```lua
LUA->Call( 0, 0 );
```

O zaman fonksiyonumu 0 argümanla çağırır ve bir geri dönüş değeri almazdı. Bir sonraki örnek 1 argümanla çağırır ve yine geri dönüş değeri almazdı:

```lua
LUA->Call( 1, 0 );
```

Bir sonraki örneğim 3 argüman geçirir ve 1 geri dönüş değeri alırdı:

```lua
LUA->Call( 3, 1 );
```

Son olarak son örneğim 2 argüman geçirir ve 4 geri dönüş değeri alırdı:

```lua
LUA->Call( 2, 4 );
```

### Call ve PCall

Call ve PCall arasındaki tek fark, PCall'un korumalı çağrı (protected call) anlamına gelmesidir. Başka bir deyişle, bir şeyler ters giderse, PCall panik yapmaz ama Call yapar. Dolayısıyla argümanlarınız sabit değilse PCall kullanmak iyi bir alışkanlıktır, ancak bu örneklerde Call kullanacağız.

### Global Tablodan Çağırma

Yani global tablodan çağırma muhtemelen en çok kullanacağınız şeydir. Global tablodan çağırmak çok basit ve kolaydır. Sadece çok güzel görünmüyor.

```lua
LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Global tabloyu it
     LUA->GetField( -1, "print" ); // print fonksiyonunu al
     LUA->PushString( "Swag" ); // Argümanımızı it
     LUA->Call( 1, 0 ); // Fonksiyonu çağır
 LUA->Pop(); // Global tabloyu yığından çek
```

Bu, konsola "Swag" çıktısı verirdi. Aşağıda birden fazla argüman kullanma örneği bulunmaktadır.

```lua
LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Global tabloyu it
     LUA->GetField( -1, "print" ); // print fonksiyonunu al
     LUA->PushString( "Swag" ); // Argümanımızı it
     LUA->PushNumber( 1337 ); // İkinci argümanımızı it
     LUA->Call( 2, 0 ); // Fonksiyonu çağır
 LUA->Pop(); // Global tabloyu yığından çek
```

Bu, konsola "Swag 1337" çıktısı verirdi. Aşağıda sözde-pratik bir kullanım örneği bulunmaktadır.

```lua
LUA_FUNCTION( MyFirstFunction )
 {
     LUA->CheckType( 1, GarrysMod::Lua::Type::String ); // İlk argümanın bir string olduğundan emin ol

     LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Global tabloyu it
         LUA->GetField( -1, "print" ); // print fonksiyonunu al
         LUA->Push( 1 ); // İlk argümanı it
         LUA->Call( 1, 0 ); // Fonksiyonu çağır
     LUA->Pop(); // Global tabloyu yığından çek

     return 0; // Kaç değer döndürdüğümüz
 }
```

Birden fazla fonksiyon çağırmak isteseydiniz, aşağıdakini yapardınız:

```lua
LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Global tabloyu it
     LUA->GetField( -1, "print" ); // print fonksiyonunu al
     LUA->PushString( "Swag" ); // Argümanımızı it
     LUA->Call( 1, 0 ); // Fonksiyonu çağır

     LUA->GetField( -1, "print" ); // print fonksiyonunu al
     LUA->PushString( "Garry feels like a new man." ); // Argümanımızı it
     LUA->Call( 1, 0 ); // Fonksiyonu çağır

     LUA->GetField( -1, "Msg" ); // Msg fonksiyonunu al
     LUA->PushString( "Double swag\n" ); // Argümanımızı it
     LUA->Call( 1, 0 ); // Fonksiyonu çağır
 LUA->Pop(); // Global tabloyu yığından çek
```

### Argüman Olarak Geçirilen Fonksiyonları Çağırma

Argüman olarak geçirilen fonksiyonları çağırmak çok faydalıdır. Başka bir bölümde bir fonksiyonu nasıl saklayacağınızı ve daha sonra nasıl çağıracağınızı ele alacağım, ama şimdilik temel bilgilerle başlayacağız.

```lua
LUA_FUNCTION( MyFirstFunction )
 {
     LUA->CheckType( 1, GarrysMod::Lua::Type::Function ); // İlk argümanın bir fonksiyon olduğundan emin ol

     LUA->PushString( "Hey... swag swag swag swag" ); // Argümanımızı it
     LUA->Push( 1 ); // Fonksiyonu it
     LUA->Call( 1, 0 ); // Fonksiyonu çağır

     return 0;
 }
```

Şimdi Lua'da aşağıdaki gibi bir şey yapsaydınız, konsola "Hey... swag swag swag swag" çıktısı verirdi.

```lua
MyFirstFunction( print )
```

### Geri Dönüş Değerini Alma

Yani fonksiyonları nasıl çağıracağınızı biliyorsunuz, sadece geri dönüş değerini nasıl alacağınızı bilmiyorsunuz. Bunu sizin için düzelteceğim. Aşağıda math.abs'in geri dönüş değerini alma örneği bulunmaktadır:

```lua
LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Global tabloyu it
     LUA->GetField( -1, "math" ); // math tablosunu al
     LUA->GetField( -1, "abs" ); // math tablosundan abs fonksiyonunu al
     LUA->PushNumber( -666 ); // Argümanımızı it
     LUA->Call( 1, 1 ); // Fonksiyonu çağır ve 1 geri dönüş değeri al

     int iReturnValue = (int)LUA->GetNumber( -1 );
 LUA->Pop( 3 ); // Global tabloyu, math tablosunu ve geri dönüş değerini yığından çek
```

Şimdi iReturnValue içinde math.abs( -666 ) fonksiyonunun geri dönüş değerine sahibiz. Yani iReturnValue 666'ya eşittir. Aşağıdaki örnekte, math.abs( 1337 ) sonucunu alıp konsoluma yazdırıyorum.

```lua
LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Global tabloyu it
     LUA->GetField( -1, "math" ); // math tablosunu al
     LUA->GetField( -1, "abs" ); // math tablosundan abs fonksiyonunu al
     LUA->PushNumber( -666 ); // Argümanımızı it
     LUA->Call( 1, 1 ); // Fonksiyonu çağır ve 1 geri dönüş değeri al

     LUA->GetField( -3, "print" ); // print fonksiyonunu al
     LUA->Push( -2 ); // Geri dönüş değerini it
     LUA->Call( 1, 0 ); // print fonksiyonunu çağır
 LUA->Pop( 3 ); // Global tabloyu, math tablosunu ve geri dönüş değerini yığından çek
```

Bu, konsoluma "666" çıktısı verirdi.

## Bir Lua Tablosu Üzerinde Yineleme.

Bir noktada, LUA'dan geçirilen bir tablo üzerinde yineleme yapmak isteyeceksiniz. Bunu yapabileceğiniz yollardan biri aşağıda gösterilmiştir.

> **NOT:** Bir anahtar veya değer tablo gibi bir şeyse muhtemelen bir tür kontrolü eklemelisiniz, çünkü değer bir tablo iken (diğer türler için de olabilir) `LUA->GetString` çağırmak bir bellek sızıntısına neden olur!

```lua
LUA_FUNCTION(Example)
{
	LUA->CheckType(1, Type::Table);
	LUA->PushNil();

	while (LUA->Next(-2)) {
		LUA->Push(-2);

		const char* key = LUA->GetString(-1);
		const char* value = LUA->GetString(-2);
		Msg("%s => %s\n", key, value); // Bunu kendi kodunuzla değiştirin.

		LUA->Pop(2);
	}

	LUA->Pop();

	return 0;
}
```

## Okunabilirlik ve kolaylık için C++ fonksiyonları oluşturma

Dahili olarak, `LUA_FUNCTION()` `LUA` değişkenini ortaya çıkaran ve içerdiği fonksiyonu Lua ile kullanılmak üzere hazırlayan bir makrodur.

Yalnızca C ortamında var olan fonksiyonlar oluşturmak için bu `LUA` değişkenini kendi fonksiyonlarımıza geçirebiliriz.

Bir fonksiyon aşağıdaki gibi tanımlanabilir:

```lua
// print() kullanarak bir mesaj yazdırır
void LuaPrint(GarrysMod::Lua::ILuaBase* LUA, char* msg)
{
	LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB); // Global tabloyu al
		LUA->GetField(-1, "print"); // print fonksiyonunu al
		LUA->PushString(msg); // String argümanını it
		LUA->Call(1, 0); // Fonksiyonu 1 argüman ve geri dönüş değeri olmadan çağır
	LUA->Pop(); // Global tabloyu çek
}
```

...ve sonra bir `LUA_FUNCTION` veya hatta `GMOD_MODULE_OPEN` içinden çağrılabilir:

```lua
GMOD_MODULE_OPEN()
{
	// Modülümüzü hazırla, Lua fonksiyonlarını yükle, vb...

	LuaPrint(LUA, "Module successfully loaded!"); // print("Modül başarıyla yüklendi!")
}
```

Verimlilik için, fonksiyonlarda ne zaman [inline](https://www.geeksforgeeks.org/inline-functions-cpp/) kullanılacağını anlamak önemlidir.

## Userdata ve metatablolar hakkında bir not

Userdata ve metatablolar Garry's Mod'da farklı şekilde ele alınır. Bu, motorun userdata türünü çok daha hızlı belirlemesine yardımcı olur.

Önce metatablonuzu oluşturun (ideal olarak GMOD_MODULE_OPEN içinde), ardından ona bir referans oluşturun ve bunu global olarak bir değişkende saklayın.

```lua
LUA->CreateTable();

     LUA->PushCFunction(gcDeleteWrapper);
     LUA->SetField(-2, "__gc");

     LUA->PushCFunction(toStringWrapper);
     LUA->SetField(-2, "__tostring");

     LUA->PushCFunction(indexWrapper);
     LUA->SetField(-2, "__index");

     LUA->PushCFunction(newIndexWrapper);
     LUA->SetField(-2, "__newindex");

 metatable = LUA->ReferenceCreate();
```

Userdata'nızı yığına itmek için:

```lua
GarrysMod::Lua::UserData* ud = ( GarrysMod::Lua::UserData* )LUA->NewUserdata( sizeof( GarrysMod::Lua::UserData ) );
     ud->data = pointer_to_your_c_class;
     ud->type = your_type_id;
     LUA->ReferencePush( metatable );
     LUA->SetMetaTable(-2);
```

Userdata'nızı yığından almak için:

```lua
GarrysMod::Lua::UserData* obj = (GarrysMod::Lua::UserData* )LUA->GetUserdata(position);
     your_c_class* var = (your_c_class*)(obj->data);
```

- [GMod Wiki ana sayfası](https://gmod.tr/wiki)

---

[Tüm sunucular](https://gmod.tr/) · [GmodTR Launcher](https://gmod.tr/launcher) · [Rehber](https://gmod.tr/rehber) · [GMod Wiki](https://gmod.tr/wiki) · [GmodTR nedir?](https://gmod.tr/hakkinda) · [Sunucu ekle](https://gmod.tr/sunucu-ekle) · [Discord](https://discord.gg/gmodtr)

Kaynak: https://gmod.tr/wiki/C_Lua:_Functions
