Kaç tane argüman iletildi?


33

Tercih ettiğiniz dili kullanarak, değişken sayıda argüman alan ve çağrıldığı argüman sayısını döndüren bir işlev yazın.

Özellikleri:

  • Dilinizin değişken değişkenli argüman işlevlerini desteklemesi gerekir: rastgele sayıda argüman alan ve bir değer döndüren çağrılabilir bir şey.
  • Parametreler ayrı ayrı geçirilebilmelidir. Bu, bir diziyi geçmenin yalnızca bir parametre için sayılacağı anlamına gelir. Diliniz destekliyorsa "tüm iletilen argümanlar" dizisini kullanabilirsiniz; kısıtlama, fonksiyonun nasıl çağrıldığı ile ilgilidir.
  • Bu işlevi çağıran kod , kaynağındaki argüman sayısını iletmek için gerekli olmamalıdır . Bir derleyici, görüşme kuralının bir parçası olarak argüman sayısını girerse, buna izin verilir.
  • Argümanlar istediğiniz türde olabilir. Yalnızca tek bir türü (örneğin, yalnızca destek inthala geçerlidir), isteğe bağlı türlerini (herhangi bir tür argümana izin verilir) veya herhangi bir argüman türünün birleşimini (örneğin, ilk argüman int, geri kalan dizelerdir) destekleyebilirsiniz.
  • İşleviniz maksimum sayıda argümana sahip olabilir (özellikle kaynaklar sınırlı olduğu için), ancak en az 2 argümanı desteklemesi gerekir .

Örnekler:

  • f() döner 0
  • f(1)veya f("a")iadeler1
  • f([1, 2, 3])döner 1bunun gibi bir dizisi, 3 argümanlar geçirilir
  • f(1, 10)veya f(1, "a")iadeler2

Bu kod golf olduğu için, kazanan çözüm en az bayt sayısını kullanan çözümdür.


4
Bir “fonksiyon”, “dönüş değeri” veya “değişken argümanlar” ın ne olduğu tamamen açık değildir (nesnel olarak). Örneğin, Dodos işlevi monadik veya variadic olarak kabul edilir mi?
user202729

24
@ user202729 Diliniz işlevleri desteklemiyorsa, başka bir dil kullanın. Bu, tüm dillerin rekabet edebilmesi için bir zorunluluk değildir, kod golfünün bir kısmı iş için doğru aracı bulmaktır.
Sanchises,

5
@ user202729 Geleneksel / üst düzey dilleri hedefleyen sık sık karşılaşılan zorluklarla ilgili sorunum yok, tıpkı yalnızca alışılmadık dillerde mümkün olan ara sıra yapılan zorluklarda olduğu gibi.
Sanchises

6
Dil karakteristikleri için durma problemini net bir sorunla çözmemiz gerektiğini bilmiyorduk ....
Conor O'Brien

5
Dilinizde argümanlar / çağrı yapma konvansiyonu kavramı yoksa, isteğe bağlı argüman sayılarını destekleme kriterlerine uymaz.
Glenn Smith

Yanıtlar:


15

BASIC'den Amstrad CPC Z80 ikili çağrısı, 1 bayt, hex kodlanmış

C9          : RET

(Ayrıca 2 ve 5 byte sürümleri, aşağıya bakınız)

Aramaya girişte, iletilen parametrelerin sayısı Akayıt defterinde olacaktır. Kod hemen geri döner. Z80'de geri dönüş değerleri kavramı yoktur, sadece giriş ve çıkış durumları vardır. Değer, sadece (orada PC) program kodu ve SP(yığın işaretçisi) haricinde, giriş koşullarını değiştirmediğinden kayıt defterinde erişilebilir "orada" dır . Bununla birlikte, içindeki değer ABASIC tarafından erişilebilir değildir ve hemen üzerine yazılır.

Örnekler:

CALL &8000, "Hello", "World"

A = 2

CALL &8000, 42

A = 1

CALL &8000

A = 0


Talep üzerine, BASIC'te değeri erişilebilir kılan bazı kodlar buradadır. Sadece 5 baytta yapılabildiğine çok şaşırdım !:

Makine kodu:

12          : LD   (DE), A
13          : INC  DE
AF          : XOR  A
12          : LD   (DE), A
C9          : RET

Girişte:

  • AF - akümülatör ve bayrak kayıtları (iki adet 8 bitlik kayıt olarak kabul edilir)
    • A En fazla 32 parametreye kadar geçirilen parametre sayısını içerir.
    • Neyin içinde olduğundan emin değilim F. Her 0ikisi de tanımlanmamış iki bayrak hariç, RESET tüm bayraklara sahip görünüyor 1. Zİçin bayrak (sıfır) SET olduğu 1geçirilen hiçbir parametre olsaydı
  • BC
    • B- 32 eksi parametre sayısı ( A+ B= 32)
    • C - &FF
  • DE - Son parametrenin adresi veya eğer hiçbir parametre iletilmediyse arama adresi
  • HL - Halen yürütülmekte olan tokenize BASIC komutundan sonraki ilk baytın adresi (bir program olarak veya anında komut modunda)
  • IX - İmlecin son parametreye kadar yığın adresi
  • IY - &0000

Kod

  1. Lo da değeri ile Dgösterilen adresDEA
  2. INCrements DE
  3. XORs A(birlikte A) veren&00
  4. Lo tarafından gösterilen adrese Dverilen değerADE
  5. RETçömleği

Çıkışta:

  • Ayok edildi (her zaman &00)
  • DE yok edilir (her zaman girişten bir tane daha yüksektir)
  • Diğer tüm kayıtlar korunur

Basit

Amstrad basic sadece üç veri tipine ve ayrıca basit dizilere sahiptir. Varsayılan olarak, tüm BASIC değişkenleri GERÇEK (işaretli, 32 bit mantis, 8 bit üstel) ve bunlar açıkça belirtilebilir !. Bir INTEGER (işaretli, 16 bit) kullanım için %ve bir STRING (1 byte string uzunluğu, 255 byte karakter verisine kadar, ikili güvenli) kullanın $:

  • x - GERÇEK (üstü kapalı)
  • x! - GERÇEK (açık)
  • x% - INTEGER
  • x$ - STRING

Ayrıca kullanabilirsiniz DEFINT, DEFREALve DEFSTRtek harfle veya iki tek harf bir dizi FORTRAN benzer o mektubu ile başlayan tüm değişkenler için varsayılan türünü belirtmek için.

  • DEFSTR a
  • DEFINT x-z

Şimdi:

  • a - STRING (örtülü)
  • i - GERÇEK (üstü kapalı)
  • x - INTEGER (örtülü)
  • x$ - STRING (açık)

Çalışılması en kolay tür tamsayıdır. Makine kodu, son parametrenin değere değil adrese göre iletilmesini beklemektedir, bu yüzden @değişkene ön ek verilmiştir. Dönüş değişkeni CALLs parametrelerinden biri olarak sayılır .

Makine kodu, BASIC'den aşağıdaki şekilde çağrılır (adrese belleğe yüklendiği varsayılarak &8000):

CALL &8000, "Hello", "World", 42, @n%

n% = 4

Bu başlangıç ​​değerinden bağımsız olarak daima doğru sonucu verecektir n%.

Tüm giriş kayıtlarını koruyan 2 baytlık bir sürüm için:

CALL &8003, "Hello", "World", 42, @n%

n% = 4

Bu ilk üç bayt atlar ve başlangıç değeri ise sadece doğru sonucu verir n%ise 0- 255. Bu işe yarar, çünkü Z80 çok azdır.

Return parametresi geçilmeden önce başlatılmalıdır, aksi takdirde BASIC bir Improper argumenthata atar . Aşağıdaki resimde, ?değişimin değerini göstermek için çağrıdan hemen önce ve sonra dönüş değerlerini (gösteriyi de golf oynadığımdan bu yana kısayolla) basıyorum. Değeri kullanıyorum, &FFFFçünkü bu -1imzalı bir tamsayı için ikili gösterimdir . Bu, 5 baytlık programın her iki baytı da doğru şekilde yazdığını gösterir, oysa 2 baytlık program sadece düşük baytları yazar ve yüksek baytın zaten var olduğunu varsayar &00.

enter image description here


Öyleyse kullandığınız arama sözleşmesi nasıl geri dönüş değerleri kullanıyor? Bunları akümülatörde veya hiç geri döndürmezse, o zaman cevabınız temel olarak, sorunu sizin için çözen özel bir arama kuralı icat etmektir ( Aeğer varsa saklayabileceğiniz bir işaretçiyi iletmek yerine, bir dönüş kaydı ekleyerek) BASIC'den nasıl yapabileceğinizi). Bunda yanlış olan bir şey yok, ancak varolan bir calliing kongresini takip etmek daha ilginç bir cevap olabilir.
Peter Cordes

@PeterCordes Amstrad BASIC veya Z80'in kapsamı kavramı yoktur. Tüm değerler küreseldir ve yok olana kadar derhal erişilebilir. AKomuttan hemen sonra değeri aynıdır RET. Bir değerin ömrü A, akümülatör olduğundan çok kısadır. Böyle bir şey yok x = CALL &8000, 42. Öyle olmak zorunda kalacak CALL &8000, x, 42ve ekstra Z80 kodu, ama sonra xolacağını 2değil 1.
CJ Dennis,

Çıkış argümanını sayıma dahil ederseniz sorun değil, aksi halde 1 baytlık bir azalma talimatı yok mu? Önemsiz olmak yerine, BASIC tarafından kullanılabilen bir sürüm görmek isterim.
Peter Cordes

1
@PeterCordes Yapıldı! Oh, bu arada, &00s - NOPno-ops ile kendi ilk iki komutunun üzerine yazacağından hiçbir parametreyle çağırmamayı söylemeyi unuttum . Daha güvenli hale getirmek için başka bir bayt eklenebilir, ancak elbette bir dönüş parametresi olmadan hiçbir şey ayarlayamaz.
CJ Dennis,

32

Java (JDK 10) , 11 bayt

a->a.length

Çevrimiçi deneyin!


29
Java'yı yenmek Javscript farkedilmesi gereken ender görülen bir şey
The rastgele adam

3
@ Therandomguy bunun interface x{void f(Object...a);}tanımlanması gibi bir şey gerektirir ve bu lambda ya bu arabirim türünün bir değişkeninde depolanmalı ya da bu arabirim türünü bekleyen bir yönteme geçirilmelidir, bu yüzden bu zorluğun önemli olduğundan emin değilim (hatta genellikle java lambdas'ın codegolf zorluklarına izin verilir)
SamYonnou

3
@SamYonnou Diğer lambdalar ile bir fark yok ve dediğiniz gibi, lambdalar gayet iyi .
Olivier Grégoire

@ OlivierGrégoire Lambdalara izin verildiğini biliyorum, demek istediğim, örneğin JavaScript ile karşılaştırıldığında, REPL gibi bir şey kullanıyor olsanız ve bir ana sınıfa / yönteme ihtiyaç duymuyorsanız bile, ayarlamak için daha fazla ekstra koda ihtiyacınız var. Arayüzün tanımlanmasına duyulan ihtiyaç, onu JavaScript'ten ayıran şeydir)
SamYonnou

@ OlivierGrégoire: Bazı Java'lar biliyorum ama bu konuya hiç uymadım. Sam'in, kazanın halı altında süpürüldüğü hakkındaki yorumunu, gerçekten kısa olmasına izin veren bir Java cevabında görmek istiyorum. İzin verilmesi gerektiğine katılıyorum (normalde Java işlevleriyle elde edemeyeceğiniz bir şey vermesine rağmen, doğru, bu nedenle yalnızca kazan plaka indirgeme değil, size argüman sayacı yerleşik olarak veriyor). Bunun yanında, "Java yenen JS" nin bir cevabı olarak hala ilginç.
Peter Cordes

25

JavaScript, 15 bayt

[].push.bind(0)

Array.prototype.pushİşlevi diziye ekler, bağımsız değişkenler herhangi bir sayıyı alır, ve dizinin boyutunu verir. Bu nedenle, pushboş bir dizide kullanılan işlev , verilen argüman sayısını döndürür push.

f = [].push.bind(0)

f(10,2,65,7)
> 4

f()
> 0

.bind(0)Sadece veren pushfonksiyonu sabit thisbir değişkene saklanabilir, böylece değer. Aslında, 7 baytlık tanımlayıcı [].pushtam anlamıyla kullanılabilir (ancak atanmamış) bind:

[].push(10,2,65,7)
> 4

[].push()
> 0

19

JavaScript (ES6), 16 bayt

(...a)=>a.length


18

Haskell , 108 107 95 94 bayt

class T r where z::Int->r
instance T Int where z=id
instance T r=>T(a->r)where z n _=z$n+1
z 0

Çevrimiçi deneyin!

Çalışmak şaşırtıcı derecede zordu, ancak zorunlu dillerde önemsiz olan bir şeyi nasıl uygulayacağımı öğrenmeye eğlendim.


Kahretsin beni yendin. Bağlama olmadan işlevi fise, isteğe bağlıdır z 0, bu yüzden main = print $ ((z 0) pi 0 () [] :: Int)çalışır.
Angs,

Ve bununla birlikte, türlerin adsız bir işlev olarak kullanıldığında çalışacağını kastediyorum, böylece gerçekten de son iki satırdaki her şeyi kaldırabilirsinizz 0
Angs

Güzel, teşekkürler! Anonim işlevi test ederken yanlış bir şey yaptığımı ortaya koyuyor. Örneğinizi denedim ve iyi çalıştı.
user9549915

Sanırım ::Intcevabın türü de olduğu gibi er ya da geç ilan edilmelidir, çünkü bayt sayısında sayılmalıdır main = print $ ((z 0 :: Double -> Integer -> () -> [a] -> (Int->Int->Int) -> IO () -> Int) pi 0 () [] (+) main). Ayrıca bunun sadece derleme sırasında çalıştığını ve böylece foldl(\a b->a b) (z 0) $ [1..5])::Intçalışamayacağını düşünüyorum. Her iki durumda da, bu harika şeyler.
Angs,

2
s/imperative/non-curry/
user202729


12

Zsh , 7 5 bayt

<<<$#

Çevrimiçi deneyin!


Muhtemelen sarılması gerekir rağmen:f(){ echo $#; }
muru

8
@muru Bu bana tam bir program gibi görünüyor.
Neil

Buna rağmen, şimdi OP'nin sadece bir işlev istediğini görüyorum ...
Neil

2
@Neil kabuk komutları tam olarak fonksiyonlara benzer. OP, bir fonksiyonun ne olduğu konusunda net değil, gönderimimin sadece diske kaydedilmiş bir fonksiyon olduğunu iddia ediyorum.
Pavel,

9

Beyin Flak , 6 bayt

İlk Brain-Flak çözümüm, göndermeye değer, sanırım bu iş için doğru araç:

([]<>)

Çevrimiçi deneyin!

açıklama

Bir Brain-Flak programı yürütülürken, başlangıçta soldaki yığın tüm değişkenleri içerir. Oradan sadece meselesi:

(      -- push the following..
 []    --   height of the stack (ie. # of arguments)
   <>  -- ..to the other stack  (toggles to the other stack)
)      --
       -- the right stack now contains the # of arguments which
       -- gets printed implicitly

7

Wolfram Dili (Mathematica) , 11 bayt

Tr[1^{##}]&

Çevrimiçi deneyin!

JungHwan Min tarafından önerildi. Bazı kısıtlamalar (giriş dikdörtgen olmalıdır) ancak isteğe bağlı girişi ele almamız gerekli değildir.

11 bayt

Length@!##&

Çevrimiçi deneyin!

Martin Ender tarafından önerilen 11 baytlık bir çözüm daha. Bu, bir giriş olmadığında hata gibi görünüyor ancak yine de her durumda doğru değeri döndürüyor.

12 bayt

Length@{##}&

Çevrimiçi deneyin!

Orijinal çözümüm.

Mathematica'da ##, bir fonksiyonda değişken sayıdaki argümanlar bulunur. {ve }onları bir listeye sarar ve Length@bu listenin uzunluğunu alır. &sonunda bunu gerçek bir işleve dönüştürür.


7

R , 30 bayt

function(...)length(list(...))

Çevrimiçi deneyin!


1
function(...)nargs()20 bayt, ancak length(...)ben nargsbenzeri bir işlevi googled kadar ilk yaklaşım benim kullanım oldu .
Giuseppe

@Giuseppe hmm, list(...)mantıklı bir hale dönüştürmeye çalıştım, böylece sum()kullanılabildi, ama bu zor: /
JAD

1
Haha, beni bu tartışmaya
sokmaya kalkma

1
@RoryT oh aslında, R docs birleştirin diyor. Boş ver: D
JAD

2
...length() aynı şeyi yaparlength(list(...))
Giuseppe

7

Bash, 12 bayt (4 tasarruf için paxdiablo'ya teşekkürler)

n()(echo $#)

Bir bash komut isteminde kopyalayıp yapıştırın. Sonra istemden n işlevini çalıştırın:

$ n
0
$ n 46 gr 3443 dad
4
$ n 4fwj23 wrw jdwj 00998 34 eyt q3 vg wq j qw
11

2
PPCG'ye Hoşgeldiniz!
Martin Ender

sadece bir betik "./n" olduğunu ve fonksiyon olmadığını söyleyebilir misiniz? o zaman sadece:, echo $#7 bayt. (o zaman "./n" betiğini başlatmak için kullanacağınız herhangi bir kabuk olacaktır. Yani, bash'ı çalıştırdınız mı? sonra ne zaman: ./n arg1 ... argnbash tarafından yorumlanacaktır.)
Olivier Dulac

@ Oliver Dulac Buradaki zorluk açıkça bir fonksiyon diyor.
Wastrel

7

C ++ 14 (gcc) , 34 bayt

Genel varyadik lambda işlevi olarak (C ++ 14 gerekli):

[](auto...p){return sizeof...(p);}

Çevrimiçi deneyin!

Önceki (yanlış) cevap: 32 bayt

Bu eksikti template<class...T>ve(p)

int f(T...p){return sizeof...p;}

6
C ++ 14, C ++ 11 'in genel lambdaları yoktur.
Quentin


@nwp: -fpermissiveBu seçenek için size 12 bayta mal olmaz mıydı ? Standart ISO C ++ veya GNU C ++ değilse.
Peter Cordes

@PeterCordes Muhtemelen, programı komut satırından geçirerek her şey için önemsiz bir 0-baytlık çözümün bulunmasından kaçınmak içindir. Bunu burada düşünmedim çünkü kötü niyetli görünmüyor.
nwp

@ Quentin sabitlendi -> C ++ 14
Bierpfurz


5

Oktav , 9 bayt

@()nargin

Çevrimiçi deneyin!

Herhangi bir sayıda argüman alarak (ve lotu sessizce atma) anonim işlev, ve yerleşik argüman sayısını yerleşik olarak verir nargin. Bu, vararginbirçok argümana keyfi olarak izin vermeniz gereken MATLAB'da çalışmaz .



4

Perl 5 , 9 bayt

sub{~~@_}

Çevrimiçi deneyin!


Cevapların hızlı bir site çapında arama dışı bırakabilir belirtmek görünüyorsub
okunur ASCII

2
Protip: TIO, PPCG posta biçiminde (ESC, S, G) kopyalayalım
yalnızca ASCII-

@ ASCII-sadece Oh güzel, teşekkürler! :) Ayrılmak için gelince sub, sanmıyorum. Onsuz bir fonksiyon değil.
Chris

@ ASCII-sadece sub, sonuçları çağırabileceğiniz veya bir değişkeni atayabileceğiniz bir şey olmadığı için cevapları geçersiz olarak kabul ederim
Ton Hospel


4

C # .NET, 11 bayt

a=>a.Length

Çevrimiçi deneyin.

Açıklama:

C #. NET'te objectçoklu tür argümanları için kullanılır, biri tamsayıları, dizeleri, karakterleri vb. Mümkün olan girişleri geçmesine izin verir. Örneğin:

// Can be called like: `F(2)`, `F("test")`, `F('a')`, etc.
void F(object arg){ ... }

C # .NET, isteğe bağlı değişkenlerin sabit bir boyutta olabilir. Örneğin:

// Can be called like: `F()`, `F(2)`, `F("test")`, `F('a')`, etc.
void F(object arg = null){ ... }

Ayrıca tanımsız miktarda isteğe bağlı argüman olan (bu cevapta kullandığım) varargs da vardır. Örneğin:

// Can be called like: `F()`, `F(2)`, `F(2, "test", 'a')`, etc.
void F(params object[] args){ ... }

Genellikle lambdas şöyle yaratılır:

System.Func<object[], int> F f = a=>a.Length;
// A call like `f(new object[]{2, "test", 'a'))` will return 3 (size of the input array)

Fakat ne yazık ki varargs'i System.Funcdesteklemiyor params, o yüzden delegatebunun yerine bir tane oluşturmam gerekecek :

delegate int F(params object[] args);
F f = a=>a.Length;
// A call like `f()` will return 0, and `f(2, "test", 'a')` will return 3

Bu zorluğa cevabım hangisi ve bağlantılı TIO test kodunda bulunabilir.


Tek sınırlama, gerçek bir object[]benzer girişin f(new object[]{1,2,3})1 yerine 3 ile f(new int[]{1,2,3})sonuçlanacağı, yine de 1 ile sonuçlanacağı, çünkü int[]tek olarak yorumladığıdır object. Sahip olmak object[]böyle bir nesneye dökülebilir sıra parametre tek bir nesne olarak yorumlamak edilebilir: f((object)new object[]{1,2,3}).


I have to say, if there were ever an answer that made me support including lambda-related boilerplate in C# answers it would be this one... but it is definitely a valid solution.
Kamil Drakari

@KamilDrakari Maybe it indeed wasn't very clear what I did without opening the TIO-link, so I've added an explanation.
Kevin Cruijssen

1
@Taemyr I tried finding a solution, but unfortunately there is none for C# .NET, except for casting any object[] parameters to object, like this: f((object)new object[]{1,2,3});. There is no way to differentiate between f(new object[]{1,2,3}); and f(1,2,3); as far as I could find.
Kevin Cruijssen

1
this handles array parameters correctly for a huge penalty of bytes. There might be a more concise structure that can handle it, but it works in my testing.
Kamil Drakari

1
@KamilDrakari Hmm, but it fails for f(1, new object[]{1,2,3}) again though. Not sure if a solution for this behavior can be found.
Kevin Cruijssen

4

Dodos, 32 31 bytes

f
	dot i f dab
i
	
	dip dot dab

Try it online!

Uses Dennis' increment function.

Explanation

f                     # definition of f - target function
        dot i f dab   # sum of j(f(all args but first)). recurses until it has 0 args
i                     # definition of i - returns (arg, 1) given 1 arg
                      # arg
        dip dot dab   # 1 (dot dab on list of length 1 returns 0, dip returns |0 - 1|)

Alternatively, 32 bytes without recursion in target function (thanks @Leo)

	dot i
i
	dip dot dab dot
	i dab

Try it online!

Explanation

        dot i             # anonymous function: sum of i(args)
                          # here this becomes implicit main
i                         # definition of i - returns a list with all arguments replaced with 1
        dip dot dab dot   # 1 (dab dot returns empty list, dot returns 0, dip returns |0 - 1|
        i dab             # list concatenated with i(all args but first)

Here's another same-length solution Try it online! I can't seem to understand why yours works though, could you add an explanation please?
Leo

Hey, you added an explanation to my solution! I wanted one for yours, I know how mine works xD
Leo

1
@Leo sorry for late reply, idek what I'm doing, just copied Dennis' function, will try to understand asap. I had no idea how dodos works so I figured out what yours did first
ASCII-only

No worries, it was just a funny situation :)
Leo

@Leo ok so does my explanation make sense? (note: I'm on mobile so feel free to edit it to make it better lol)
ASCII-only

3

C++, 72 bytes

int f(){return 0;}template<class...P>int f(int,P...p){return f(p...)+1;}

Saves bytes by only working with ints.


You can use sizeof....
L. F.

3

Rust, 57 bytes

macro_rules!f{()=>{0};($($x:expr),+)=>{[$($x),+].len()};}

Explanation:

macro_rules! f {         // define a macro called f
    () => {0};           // when called without arguments, expand to 0
    ($($x:expr),+) => {  // when called with 1 or more comma seperated arguments
        [                // rust uses [a, b, c] to make an array
            $($x),+      // expand to the arguments seperated with a comma
        ]                
        .len()           // take the length of that.
    };
}

Test:

fn main() {
    println!("{:?}", f!());                // prints 0
    println!("{:?}", f!(4));               // prints 1
    println!("{:?}", f!(5, 2));            // prints 2
    // works with anything, as long as you dont mix things
    println!("{}", f!("", "a", "hello"));  // prints 3
}




2

PHP, 11 bytes

<?=$argc-1;

Try it online: 1 input | 3 inputs


I'm not so sure about this one (and it's validity) since it is the count of arguments passed to call PHP.
Ismael Miguel

@IsmaelMiguel, see this consensus.
Shaggy

1
The question explicitly requires a function that returns the number, does not display it: "...write a function that takes a variable number of arguments and returns the number of arguments."
axiac

1
Re-quoting the question: "Using your language of choice, write a function that takes a variable number of arguments and returns the number of arguments it was called with.". Your code doesn't contain functions.
Ismael Miguel

@IsmaelMiguel, if that were indeed the case then many other solutions would also be invalidated. The norm is to allow solutions to be programmes or functions.
Shaggy

2

Batch, 50 49 bytes

set n=0
for %%a in (%*)do set/an+=1
exit/b%n%

No builtin in Batch, so we have to go old-school. Saved 1 byte thanks to @IsmaelMiguel. Outputs via exit code, or save 3 bytes if output via global variable is valid. Example of use in a full program:

@echo off
call:c %*
echo %ERRORLEVEL%
exit/b
:c
set n=0
for %%a in (%*)do set/an+=1
exit/b%n%

I believe that this answer is answer goes (somewhat) against the rules. Batch has something somewhat close to functions. You can do something similar to :a|set r=0&for %%a in (%*)do set/ar+=1 (| = windows-style newline). This solution is 38 bytes. To execute it, do call :a <args> with a goto :eof before the function, being the value available inside the variable r. If you want to keep your solution, remove the /a on the first set, and remove those @.
Ismael Miguel

@IsmaelMiguel Like this? (Note: I didn't include the function name in the byte count, but I did include the function return, which seems reasonable, as there needs to be one somewhere.)
Neil

Yes, that's exactly it. Nice catch with the exit code! I was surprised to see that exitcodes can be larger than 255. An example is the list provided by Symantec: symantec.com/connect/articles/…
Ismael Miguel

2

x86 32-bit (i386) machine code function, 13 bytes

Calling convention: i386 System V (stack args), with a NULL pointer as a sentinel / terminator for the end-of-arg-list. (Clobbers EDI, otherwise complies with SysV).

C (and asm) don't pass type info to variadic functions, so the OP's description of passing integers or arrays with no explicit type info could only be implemented in a convention that passed some kind of struct / class object (or pointers to such), not bare integers on the stack. So I decided to assume that all the args were non-NULL pointers, and the caller passes a NULL terminator.

A NULL-terminated pointer list of args is actually used in C for functions like POSIX execl(3): int execl(const char *path, const char *arg, ... /* (char *) NULL */);

C doesn't allow int foo(...); prototypes with no fixed arg, but int foo(); means the same thing: args unspecified. (Unlike in C++ where it means int foo(void)). In any case, this is an asm answer. Coaxing a C compiler to call this function directly is interesting but not required.

nasm -felf32 -l/dev/stdout arg-count.asm with some comment lines removed.

24                       global argcount_pointer_loop
25                       argcount_pointer_loop:
26                               .entry:
28 00000000 31C0             xor   eax, eax  ; search pattern = NULL
29 00000002 99               cdq             ; counter = 0
30 00000003 89E7             mov   edi, esp
31                       ;    scasd           ; edi+=4; skip retaddr
32                       .scan_args:
33 00000005 42               inc   edx
34 00000006 AF               scasd            ; cmp eax,[edi] / edi+=4
35 00000007 75FC             jne  .scan_args
36                       ;    dec   edx       ; correct for overshoot: don't count terminator
37                       ;    xchg  eax,edx
38 00000009 8D42FE           lea   eax, [edx-2]    ; terminator + ret addr
40 0000000C C3               ret

size = 0D               db $ - .entry

The question shows that the function must be able to return 0, and I decided to follow that requirement by not including the terminating NULL pointer in the arg count. This does cost 1 byte, though. (For the 12-byte version, remove the LEA and uncomment the scasd outside the loop and the xchg, but not the dec edx. I used LEA because it costs the same as those other three instructions put together, but is more efficient, so the function is fewer uops.)

C caller for testing:

Built with:

nasm -felf32 -l /dev/stdout arg-count.asm | cut -b -28,$((28+12))- &&
 gcc -Wall -O3 -g -std=gnu11 -m32 -fcall-used-edi arg-count.c arg-count.o -o ac &&
 ./ac

-fcall-used-edi is required even at -O0 to tell gcc to assume that functions clobber edi without saving/restoring it, because I used so many calls in one C statement (the printf call) that even -O0 was using EDI. It appears to be safe for gcc's main to clobber EDI from its own caller (in CRT code), on Linux with glibc, but otherwise it's totally bogus to mix/match code compiled with different -fcall-used-reg. There's no __attribute__ version of it to let us declare the asm functions with custom calling conventions different from the usual.

#include <stdio.h>

int argcount_rep_scas();       // not (...): ISO C requires at least one fixed arg
int argcount_pointer_loop();   // if you declare args at all
int argcount_loopne();

#define TEST(...) printf("count=%d = %d = %d   (scasd/jne) | (rep scas) | (scas/loopne)\n", \
        argcount_pointer_loop(__VA_ARGS__), argcount_rep_scas(__VA_ARGS__), \
        argcount_loopne(__VA_ARGS__))

int main(void) {
    TEST("abc", 0);
    TEST(1, 1, 1, 1, 1, 1, 1, 0);
    TEST(0);
}

Two other versions also came in at 13 bytes: this one based on loopne returns a value that's too high by 1.

45                       global argcount_loopne
46                       argcount_loopne:
47                           .entry:
49 00000010 31C0             xor   eax, eax  ; search pattern = NULL
50 00000012 31C9             xor   ecx, ecx  ; counter = 0
51 00000014 89E7             mov   edi, esp
52 00000016 AF               scasd           ; edi+=4; skip retaddr
53                       .scan_args:
54 00000017 AF               scasd
55 00000018 E0FD             loopne  .scan_args
56 0000001A 29C8             sub   eax, ecx
58 0000001C C3               ret

size = 0D = 13 bytes               db $ - .entry

This version uses rep scasd instead of a loop, but takes the arg count modulo 256. (Or capped at 256 if the upper bytes of ecx are 0 on entry!)

63                       ; return int8_t maybe?
64                       global argcount_rep_scas
65                       argcount_rep_scas:
66                               .entry:
67 00000020 31C0             xor   eax, eax
68                           ;    lea   ecx, [eax-1]
69 00000022 B1FF             mov   cl, -1
70 00000024 89E7             mov   edi, esp
71                       ;    scasd              ; skip retaddr
72 00000026 F2AF             repne scasd        ; ecx = -len - 2 (including retaddr)
73 00000028 B0FD             mov   al, -3
74 0000002A 28C8             sub   al, cl       ; eax = -3 +len + 2
75                       ;    dec   eax
76                       ;    dec   eax
77 0000002C C3               ret

size =  0D = 13 bytes         db $ - .entry

Amusingly, yet another version based on inc eax / pop edx / test edx,edx / jnz came in at 13 bytes. It's a callee-pops convention, which is never used by C implementations for variadic functions. (I popped the ret addr into ecx, and jmp ecx instead of ret. (Or push/ret to not break the return-address predictor stack).



1

JavaScript, 35 bytes

f=
function(){return arguments.length}

console.log(f(2,5,4))


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.