Ile argumentów zostało przekazanych?


33

Używając wybranego języka, napisz funkcję, która pobiera zmienną liczbę argumentów i zwraca liczbę argumentów, z którymi została wywołana.

Specyfika:

  • Twój język musi obsługiwać różne funkcje argumentów: coś, co wymaga dowolnej liczby argumentów i zwraca wartość.
  • Parametry muszą być przekazywane indywidualnie. Oznacza to, że przekazanie tablicy będzie liczyło się tylko dla jednego parametru. Możesz użyć tablicy „wszystkie przekazane argumenty”, jeśli Twój język ją obsługuje; ograniczenie dotyczy sposobu wywoływania funkcji.
  • Kod wywołujący tę funkcję nie może być wymagany do przekazania liczby argumentów w źródle . Jeśli kompilator wstawi liczbę argumentów jako część konwencji wywoływania, jest to dozwolone.
  • Argumenty mogą być dowolnego typu. Możesz obsługiwać tylko jeden typ (np. Tylko obsługa intjest nadal ważna), dowolne typy (dozwolony jest dowolny typ argumentu) lub dowolna kombinacja typów argumentów (np. Pierwszy argument to intreszta to łańcuchy).
  • Twoja funkcja może mieć maksymalną liczbę argumentów (zwłaszcza, że ​​zasoby są skończone), ale musi obsługiwać co najmniej 2 argumenty.

Próbki:

  • f() zwraca 0
  • f(1)lub f("a")wraca1
  • f([1, 2, 3])zwraca, 1gdy jest przekazywana tablica, a nie 3 argumenty
  • f(1, 10)lub f(1, "a")wraca2

Ponieważ jest to gra w golfa kodowego, zwycięskim rozwiązaniem jest takie, które wykorzystuje najmniejszą liczbę bajtów.


4
Nie jest do końca jasne (obiektywnie), co to jest „funkcja”, „wartość zwracana” lub „argumenty variadic”. Na przykład, czy funkcję Dodos można uznać za monadyczną czy variadyczną?
user202729,

24
@ user202729 Jeśli twój język nie obsługuje funkcji, użyj innego języka. Nie jest wymagane, aby wszystkie języki mogły ze sobą konkurować, częścią gry w golfa jest znalezienie odpowiedniego narzędzia do pracy.
Sanchises,

5
@ user202729 Nie mam problemów z okazjonalnym wyzwaniem skierowanym do języków tradycyjnych / wysokiego poziomu, podobnie jak sporadyczne wyzwanie, które jest możliwe tylko w nietypowych językach.
Sanchises

6
nie wiedziałem, że musieliśmy rozwiązać problem z zatrzymaniem, aby cechy językowe miały wyraźne wyzwanie ...
Conor O'Brien

5
Jeśli twój język nie ma pojęcia argumentów / konwencji wywoływania, to nie spełnia kryteriów obsługi dowolnej liczby argumentów.
Glenn Smith,

Odpowiedzi:


15

Amstrad CPC Z80 wywołanie binarne z języka BASIC, 1 bajt, kodowane szesnastkowo

C9          : RET

(Również wersje 2 i 5 bajtowe, patrz poniżej)

Po wejściu do rozmowy liczba przekazanych parametrów będzie w Arejestrze. Kod po prostu zwraca natychmiast. W Z80 nie ma pojęcia wartości zwracanych, tylko stany wejścia i wyjścia. Wartość jest po prostu „dostępna” w rejestrze, ponieważ kod nie zmienia żadnych warunków wejściowych, z wyjątkiem PC(licznika programu) i SP(wskaźnika stosu). Jednak wartość in Anie jest dostępna dla BASICa i zostaje niemal natychmiast zastąpiona.

Przykłady:

CALL &8000, "Hello", "World"

A = 2

CALL &8000, 42

A = 1

CALL &8000

A = 0


Na życzenie oto kod, który udostępnia wartość w języku BASIC. Byłem bardzo zaskoczony, gdy udało mi się to zrobić w zaledwie 5 bajtów !:

Kod maszynowy:

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

Przy wejściu:

  • AF - rejestry akumulatorów i flag (traktowane jako dwa rejestry 8-bitowe)
    • A zawiera liczbę przekazanych parametrów, maksymalnie do 32 parametrów
    • Nie jestem pewien, co jest w środku F. Wygląda na to, że wszystkie flagi zostały RESETOWANE 0, z wyjątkiem dwóch niezdefiniowanych flag, które są obydwoma 1. ZFlag (zero) jest ustawiony 1, jeśli nie zostały przekazane w żadnych parametrów
  • BC
    • B- 32 minus liczba parametrów ( A+ B= 32)
    • C - &FF
  • DE - Adres ostatniego parametru lub adres wywołujący, jeśli nie przekazano żadnych parametrów
  • HL - Adres pierwszego bajtu po aktualnie wykonywanym tokenizowanym poleceniu BASIC (jako program lub w trybie polecenia natychmiastowego)
  • IX - Adres stosu wskaźnika do ostatniego parametru
  • IY - &0000

Kod

  1. LOA Ds adres wskazywany przez DEz wartością wA
  2. INCrements DE
  3. XORs A(z A), dając&00
  4. LOA Ds wartość Ado adresu wskazywanego przezDE
  5. RETurny

Przy wyjściu:

  • Ajest zniszczony (zawsze &00)
  • DE jest zniszczony (zawsze o jeden wyższy niż przy wejściu)
  • Wszystkie inne rejestry są zachowane

Podstawy

Amstrad basic ma tylko trzy typy danych oraz proste tablice. Domyślnie wszystkie zmienne BASIC są PRAWDZIWE (podpisane, 32-bitowa mantysa, 8-bitowy wykładnik), co można jednoznacznie określić !. W przypadku użycia INTEGER (podpisany, 16 bitów) %i STRING (długość łańcucha 1 bajt, dane do 255 bajtów, sejf binarny) $:

  • x - PRAWDZIWE (niejawne)
  • x! - PRAWDZIWE (jednoznaczne)
  • x% - INTEGER
  • x$ - STRUNOWY

Można również użyć DEFINT, DEFREALi DEFSTRz jednej litery lub zakresu dwoma pojedynczymi literami, aby określić typ domyślny dla wszystkich zmiennych wyjściowych z tego pisma, podobnie jak FORTRAN.

  • DEFSTR a
  • DEFINT x-z

Teraz:

  • a - STRING (domyślnie)
  • i - PRAWDZIWE (niejawne)
  • x - INTEGER (domyślnie)
  • x$ - STRING (jednoznaczne)

Najłatwiejszym typem do pracy jest liczba całkowita. Kod maszynowy oczekuje, że ostatni parametr zostanie przekazany przez adres, a nie wartość, dlatego @jest poprzedzony zmienną. Zmienna zwracana jest liczona jako jeden z CALLparametrów s.

Kod maszynowy jest wywoływany z BASIC w następujący sposób (przy założeniu, że jest załadowany do pamięci pod adresem &8000):

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

n% = 4

To zawsze daje poprawny wynik, niezależnie od wartości początkowej n%.

W przypadku wersji 2-bajtowej, która zachowuje wszystkie rejestry wejściowe:

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

n% = 4

Pomija to pierwsze trzy bajty i daje poprawny wynik tylko wtedy, gdy początkowa wartość n%to 0- 255. Działa to, ponieważ Z80 jest little-endian.

Parametr zwracany musi zostać zainicjowany przed przekazaniem, w przeciwnym razie BASIC zgłosi Improper argumentbłąd. Na poniższym obrazku drukuję (skrótem, ?ponieważ grałem też w grę!) Wartości zwracane bezpośrednio przed i po wywołaniu, aby pokazać zmianę wartości. Używam tej wartości, &FFFFponieważ jest to reprezentacja binarna -1dla liczby całkowitej ze znakiem. To pokazuje, że program 5-bajtowy poprawnie zapisuje oba bajty, podczas gdy program 2-bajtowy zapisuje tylko bajt niski i zakłada, że ​​bajt najwyższy już istnieje &00.

wprowadź opis zdjęcia tutaj


Więc w jaki sposób konwencja wywoływania używa wartości zwracanych? Jeśli nie zwróci ich w akumulatorze lub w ogóle, twoją odpowiedzią jest w zasadzie wymyślenie niestandardowej konwencji wywoływania, która rozwiązuje problem dla ciebie (poprzez dodanie rejestru zwrotnego, zamiast przekazywania wskaźnika, w którym można zapisać A, jeśli to jest jak możesz to zrobić z poziomu BASIC). Nie chodzi o to, że jest w tym coś złego, ale może być ciekawszą odpowiedzią na przestrzeganie istniejącej konwencji calli.
Peter Cordes,

@PeterCordes Ani Amstrad BASIC, ani Z80 nie mają pojęcia o zakresach. Wszystkie wartości są globalne i są natychmiast dostępne, dopóki nie zostaną zniszczone. Wartość Ajest taka sama natychmiast po RETinstrukcji. Żywotność wartości w Ajest bardzo krótka, ponieważ jest to akumulator. Nie ma czegoś takiego jak x = CALL &8000, 42. Musiałby to być CALL &8000, x, 42, i dodatkowy kod Z80, ale wtedy xbyłoby 2nie 1.
CJ Dennis,

Myślę, że to w porządku, jeśli podasz argument wyjściowy arg do zliczenia, w przeciwnym razie istnieje instrukcja dekrementacji 1-bajtowej, prawda? Chciałbym zobaczyć wersję, która faktycznie byłaby użyteczna z BASIC-a, zamiast być trywialna.
Peter Cordes,

1
@PeterCordes Gotowe! A tak przy okazji, zapomniałem wspomnieć, aby nie wywoływać go bez parametrów, ponieważ zastąpi on swoje pierwsze dwie instrukcje &00s - NOPno-ops. Można dodać kolejny bajt, aby uczynić go bezpieczniejszym, ale oczywiście bez parametru zwracającego nie może niczego ustawić.
CJ Dennis,

32

Java (JDK 10) , 11 bajtów

a->a.length

Wypróbuj online!


29
Java pokonująca Javscript jest rzadką do zauważenia
przypadkowy facet

3
@Therandomguy wymaga interface x{void f(Object...a);}to zdefiniowania, a ta lambda musi być albo zapisana w zmiennej tego typu interfejsu, albo przekazana do metody oczekującej tego typu interfejsu, więc nie jestem pewien, czy liczy się to wyzwanie (nawet choć zwykle javanki są dozwolone w wyzwaniach codegolf)
SamYonnou,

3
@SamYonnou Nie ma różnicy z innymi lambdami, a jak wspomniałeś, lambdas są w porządku .
Olivier Grégoire,

@ OlivierGrégoire Wiem, że lambdy są dozwolone, miałem na myśli, że w porównaniu do JavaScript, na przykład, potrzebujesz dużo więcej kodu, aby go skonfigurować, nawet jeśli używasz czegoś takiego jak REPL i unikasz potrzeby głównej klasy / metody ( potrzeba zdefiniowania interfejsu jest tym, co odróżnia go od JavaScript)
SamYonnou 11.04.18

@ OlivierGrégoire: Znam trochę Javy, ale wcale jej nie nadążam. Byłem zainteresowany, aby zobaczyć komentarz Sama na temat tego, jak płyta kotłowa jest zamiatana pod dywanikiem w odpowiedzi w Javie, która pozwala, aby była naprawdę krótka. Zgadzam się, że powinno być dozwolone (nawet jeśli daje ci coś, czego normalnie nie dostajesz dzięki funkcjom Java, prawda, więc nie jest to tylko redukcja kotła, ale wbudowane liczenie argów). Poza tym nadal jest interesująca jako odpowiedź na „Java pokonującą JS”.
Peter Cordes,

25

JavaScript, 15 bajtów

[].push.bind(0)

Array.prototype.pushFunkcja przyjmuje dowolną liczbę argumentów, dodaje je do swojej tablicy i zwraca rozmiar tablicy. Dlatego pushfunkcja użyta w pustej tablicy zwraca liczbę dostarczonych argumentów push.

f = [].push.bind(0)

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

f()
> 0

Po .bind(0)prostu nadaje pushfunkcji stałą thiswartość, dzięki czemu można ją zapisać w zmiennej. W rzeczywistości 7-bajtowy identyfikator [].pushmoże być używany dosłownie (ale nie przypisany) bez bind:

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

[].push()
> 0


18

Haskell , 108 107 95 94 bajtów

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

Wypróbuj online!

To było zaskakująco trudne, ale dobrze się bawiłem, próbując dowiedzieć się, jak wdrożyć coś, co jest trywialne w imperatywnych językach.


Cholera, pobiłeś mnie do tego. fjest opcjonalne, jeśli powiesz, że z 0jest funkcją bez powiązania, więc main = print $ ((z 0) pi 0 () [] :: Int)działa.
Angs

Rozumiem przez to, że typy działają, gdy są używane jako funkcja anonimowa, dzięki czemu można rzeczywiście usunąć wszystko z dwóch ostatnich wierszy z wyjątkiemz 0
Angs

Fajnie dzięki! Okazuje się, że robiłem coś złego, kiedy testowałem anonimową funkcję. Wypróbowałem twój przykład i działało dobrze.
user9549915 10.0418

Myślę, że ::Intnależy je liczyć w liczbie bajtów, ponieważ rodzaj odpowiedzi musi zostać zadeklarowany prędzej czy później, jak w main = print $ ((z 0 :: Double -> Integer -> () -> [a] -> (Int->Int->Int) -> IO () -> Int) pi 0 () [] (+) main). Myślę też, że działa to tylko podczas kompilacji, więc coś takiego foldl(\a b->a b) (z 0) $ [1..5])::Intnie działa. Tak czy inaczej, to świetne rzeczy.
Angs

2
s/imperative/non-curry/
user202729,


12

Zsh , 7 5 bajtów

<<<$#

Wypróbuj online!


Chociaż prawdopodobnie powinien być zawinięty:f(){ echo $#; }
muru,

8
@muru To dla mnie wygląda dobrze jako pełny program.
Neil,

Chociaż widzę teraz, że OP chce tylko funkcji ...
Neil

2
Skrypty powłoki @Neil działają dokładnie tak jak funkcje. OP nie wyjaśnia, co to jest funkcja, twierdzę, że moje przesłanie jest tylko funkcją zapisaną na dysku.
Pavel

9

Brain-Flak , 6 bajtów

Moje pierwsze rozwiązanie Brain-Flak godne opublikowania, myślę, że jest to właściwe narzędzie do tego zadania:

([]<>)

Wypróbuj online!

Wyjaśnienie

Podczas wykonywania programu Brain-Flak początkowo lewy stos zawiera wszystkie argumenty. Stamtąd jest to po prostu kwestia:

(      -- 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 Language (Mathematica) , 11 bajtów

Tr[1^{##}]&

Wypróbuj online!

Sugerowane przez JungHwan Min. Niektóre ograniczenia (dane wejściowe muszą być prostokątne), ale nie jesteśmy zobowiązani do obsługi danych arbitralnych.

11 bajtów

Length@!##&

Wypróbuj online!

Kolejne 11-bajtowe rozwiązanie zaproponowane przez Martina Endera. Wydaje się, że to błąd, gdy nie ma jednego wejścia, ale nadal zwraca poprawną wartość we wszystkich przypadkach.

12 bajtów

Length@{##}&

Wypróbuj online!

Moje oryginalne rozwiązanie.

W Mathematica ##oznacza różnorodną liczbę argumentów w funkcji. {i }zawija je w listę i Length@zajmuje długość tej listy. &na końcu zamienia to w faktyczną funkcję.


7

R , 30 bajtów

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

Wypróbuj online!


1
function(...)nargs()ma 20 bajtów, ale length(...)początkowo korzystałem z niego, dopóki nie przejrzałem nargsfunkcji podobnej do Google.
Giuseppe,

@Giuseppe hmm, próbowałem przekonwertować na list(...)logiczny, więc sum()można go użyć, ale to trudne: /
JAD

1
Haha, nie próbuj
przekonywać

1
@RoryT och, tak, R doktorzy mówią połączyć. Nevermind: D
JAD

2
...length() robi to samo, colength(list(...))
Giuseppe,

7

Bash, 12 bajtów (dzięki paxdiablo za oszczędność 4)

n()(echo $#)

Skopiuj i wklej po wyświetleniu monitu. Następnie uruchom funkcję n z wiersza polecenia:

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

2
Witamy w PPCG!
Martin Ender,

czy możesz po prostu powiedzieć, że jest to skrypt „./n”, a nie funkcja? to jest po prostu echo $#:, 7 bajtów. (będzie to jakakolwiek powłoka, której użyjesz do uruchomienia skryptu „./n” za pomocą. tzn. uruchomisz bash? a potem, gdy: ./n arg1 ... argnzostanie to zinterpretowane przez bash.)
Olivier Dulac

@Olivier Dulac Wyzwanie wyraźnie mówi o funkcji.
Wastrel

7

C ++ 14 (gcc) , 34 bajty

Jako ogólna variadyczna funkcja lambda (wymagany C ++ 14):

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

Wypróbuj online!

Poprzednia (niepoprawna) odpowiedź: 32 bajty

Brakowało template<class...T>i(p)

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

6
C ++ 14, C ++ 11 nie ma ogólnych lambd.
Quentin,

1
Możesz dodać flagę permissive, aby móc usunąć nawias wokółp (i -wwyłączyć ostrzeżenie).
nwp

@nwp: czy nie -fpermissivekosztowałbyś 12 bajtów dla tej opcji? Jeśli nie jest to standard ISO C ++ lub GNU C ++.
Peter Cordes,

@PeterCordes Prawdopodobnie działa i ma na celu uniknięcie trywialnego rozwiązania 0-bajtowego na wszystko, przekazując program za pomocą wiersza poleceń. Po prostu o tym tutaj nie myślałem, ponieważ wydaje się, że nie jest to obelżywe.
nwp 12.04.18

@Quentin naprawiono -> C ++ 14
Bierpfurz


5

Oktawa , 9 bajtów

@()nargin

Wypróbuj online!

Anonimowa funkcja pobierająca dowolną liczbę argumentów (i dyskretnie odrzucająca partię), i wysyła liczbę argumentów przez wbudowane nargin. Nie działa to w MATLAB, gdzie trzeba vararginby pozwolić na dowolne wiele argumentów.





4

C # .NET, 11 bajtów

a=>a.Length

Wypróbuj online.

Wyjaśnienie:

W języku C # .NET objectjest używany do argumentów wielu typów, umożliwiając przekazywanie liczb całkowitych, ciągów, znaków itp. Jako możliwych danych wejściowych. Na przykład:

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

C # .NET może również mieć ustalony rozmiar opcjonalnych argumentów. Na przykład:

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

Są też varargs, czyli nieokreślona liczba opcjonalnych argumentów (tego właśnie użyłem w tej odpowiedzi). Na przykład:

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

Zazwyczaj lambdas są tworzone w ten sposób:

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)

Ale niestety System.Funcnie obsługuje paramsvarargs, więc delegatezamiast tego będę musiał utworzyć :

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

To moja odpowiedź na to wyzwanie, którą można znaleźć w połączonym kodzie testowym TIO.


Jedynym ograniczeniem jest to, że wprowadzenie rzeczywistej wartości object[]podobnej f(new object[]{1,2,3})spowoduje 3 zamiast 1 f(new int[]{1,2,3}), nadal spowoduje 1, ponieważ interpretuje to int[]jako pojedynczy object. Aby mieć object[]parametr należy interpretować jako pojedynczego obiektu, jak również może być lanego do obiektu tak: f((object)new object[]{1,2,3}).


Muszę powiedzieć, że gdyby kiedykolwiek istniała odpowiedź, która poparłaby mnie, włączając w to odpowiedź kotła związaną z lambda w odpowiedziach C #, byłaby to ta ... ale jest to z pewnością prawidłowe rozwiązanie.
Kamil Drakari,

@KamilDrakari Może rzeczywiście nie było bardzo jasne, co zrobiłem bez otwarcia łącza TIO, więc dodałem wyjaśnienie.
Kevin Cruijssen

1
@Taemyr Próbowałem znaleźć rozwiązanie, ale niestety nie ma nikogo do C # .NET, z wyjątkiem rzucania żadnych object[]parametrów, aby objectcoś takiego: f((object)new object[]{1,2,3});. Nie ma sposobu na rozróżnienie pomiędzy f(new object[]{1,2,3});i f(1,2,3);o ile mogłem znaleźć.
Kevin Cruijssen

1
to poprawnie obsługuje parametry tablicy, co powoduje ogromną karę bajtów. Może istnieć bardziej zwięzła struktura, która może to obsłużyć, ale działa w moich testach.
Kamil Drakari,

1
@KamilDrakari Hmm, ale to f(1, new object[]{1,2,3})znowu się nie udaje . Nie jestem pewien, czy można znaleźć rozwiązanie tego problemu.
Kevin Cruijssen

4

Dodos , 32 31 bajtów

f
	dot i f dab
i
	
	dip dot dab

Wypróbuj online!

Używa funkcji przyrostowej Dennisa.

Wyjaśnienie

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|)

Alternatywnie, 32 bajty bez rekurencji w funkcji celu (dzięki @Leo )

	dot i
i
	dip dot dab dot
	i dab

Wypróbuj online!

Wyjaśnienie

        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)

Oto inne rozwiązanie tej samej długości Wypróbuj online! Wydaje mi się, że nie rozumiem, dlaczego twój działa, czy mógłbyś dodać wyjaśnienie?
Leo

Hej, dodałeś wyjaśnienie do mojego rozwiązania! Chciałem jeden dla ciebie, wiem jak działa mój xD
Leo

1
@Leo przepraszam za spóźnioną odpowiedź, idek co robię, właśnie skopiowałem funkcję Dennisa, postaram się zrozumieć jak najszybciej. Nie miałem pojęcia, jak działa dodos, więc najpierw zorientowałem się, co zrobiłeś
tylko ASCII

Bez obaw, to była po prostu zabawna sytuacja :)
Leo

@Leo ok, więc czy moje wyjaśnienie ma sens? (uwaga: korzystam z telefonu komórkowego, więc możesz go edytować, aby poprawić lol)
tylko ASCII

3

C ++, 72 bajty

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

Oszczędza bajty, pracując tylko z ints.


Możesz użyć sizeof....
LF

3

Rdza, 57 bajtów

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

Wyjaśnienie:

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 bajtów

<?=$argc-1;

Wypróbuj online: 1 wejście | 3 wejścia


Nie jestem tego pewien (i jego poprawności), ponieważ jest to liczba argumentów przekazanych do wywołania PHP.
Ismael Miguel,

@ IsmaelMiguel, zobacz ten konsensus .
Kudłaty

1
Pytanie wyraźnie wymaga funkcji, która zwraca liczbę, nie wyświetla jej: „... napisz funkcję, która pobiera zmienną liczbę argumentów i zwraca liczbę argumentów”.
axiac

1
Ponownie cytując pytanie: „Używając wybranego języka, napisz funkcję, która pobiera zmienną liczbę argumentów i zwraca liczbę argumentów, z którymi została wywołana.”. Twój kod nie zawiera funkcji.
Ismael Miguel,

@ IsmaelMiguel, gdyby tak rzeczywiście było, wówczas wiele innych rozwiązań również zostałoby unieważnionych. Normą jest dopuszczanie rozwiązań, które mogą być programami lub funkcjami.
Kudłaty

2

Partia, 50 49 bajtów

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

Brak wbudowanego w Batch, więc musimy iść do starej szkoły. Zapisano 1 bajt dzięki @IsmaelMiguel. Dane wyjściowe za pomocą kodu wyjścia lub zapisanie 3 bajtów, jeśli dane wyjściowe za pomocą zmiennej globalnej są prawidłowe. Przykład zastosowania w pełnym programie:

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

Uważam, że ta odpowiedź jest odpowiedzią (nieco) sprzeczną z zasadami. Batch ma coś podobnego do funkcji. Możesz zrobić coś podobnego do :a|set r=0&for %%a in (%*)do set/ar+=1( |= nowa linia w stylu Windows). To rozwiązanie ma 38 bajtów. Aby go wykonać, wykonaj call :a <args>z goto :eoffunkcją przed, która jest wartością dostępną wewnątrz zmiennej r. Jeśli chcesz zachować swoje rozwiązanie, usuń /apierwszy seti usuń je @.
Ismael Miguel

@IsmaelMiguel Podoba Ci się to? (Uwaga: nie uwzględniłem nazwy funkcji w liczbie bajtów, ale uwzględniłem zwrot funkcji, co wydaje się rozsądne, ponieważ gdzieś musi istnieć.)
Neil

Tak, właśnie o to chodzi. Niezły chwyt z kodem wyjścia! Byłem zaskoczony, widząc, że kody wyjściowe mogą być większe niż 255. Przykładem jest lista dostarczona przez Symantec: symantec.com/connect/articles/…
Ismael Miguel

2

x86 32-bitowa (i386) funkcja kodu maszynowego, 13 bajtów

Konwencja wywoływania : i386 System V (stos argumentów), ze wskaźnikiem NULL jako wartownikiem / terminatorem listy końca argumentu . (Clobbers EDI, poza tym zgodny z SysV).

C (i asm) nie przekazują informacji o typie do funkcji variadic, więc opis OP dotyczący przekazywania liczb całkowitych lub tablic bez wyraźnych informacji o typie może być zaimplementowany tylko w konwencji, która przekazała jakiś obiekt struct / class (lub wskaźniki do takich ), a nie same liczby całkowite na stosie. Postanowiłem więc założyć, że wszystkie argumenty nie były wskaźnikami NULL, a obiekt wywołujący przechodzi terminator NULL.

Lista wskaźników zakończona wartością NULL argumentów jest faktycznie używana w C dla funkcji takich jak POSIXexecl(3) : int execl(const char *path, const char *arg, ... /* (char *) NULL */);

C nie zezwala na int foo(...);prototypy bez ustalonego arg, ale int foo();oznacza to samo: args nieokreślony. (W przeciwieństwie do C ++, gdzie to oznacza int foo(void)). W każdym razie jest to odpowiedź asm. Koncentrowanie kompilatora C w celu bezpośredniego wywołania tej funkcji jest interesujące, ale nie wymagane.

nasm -felf32 -l/dev/stdout arg-count.asm z usuniętymi niektórymi wierszami komentarza.

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

Pytanie pokazuje, że funkcja musi mieć możliwość zwrócenia 0, i postanowiłem spełnić to wymaganie, nie włączając końcowego wskaźnika NULL do liczby argumentów. Jednak kosztuje to 1 bajt. (W przypadku wersji 12-bajtowej usuń LEA i odkomentuj scasdzewnętrzną pętlę i xchg, ale nie dec edx. Użyłem LEA, ponieważ kosztuje tyle samo, co pozostałe trzy instrukcje razem, ale jest bardziej wydajna, więc funkcja jest mniejsza ups.)

Osoba dzwoniąca C do testowania :

Zbudowany z:

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-edijest wymagane nawet przy -O0, aby powiedzieć gcc, aby zakładał, że funkcje zamykają się edibez zapisywania / przywracania, ponieważ użyłem tak wielu wywołań w jednej instrukcji C ( printfwywołanie), że nawet -O0używał EDI. Wydaje się, że gcc może bezpiecznie mainzablokować EDI z własnego obiektu wywołującego (w kodzie CRT), w Linuksie z glibc, ale poza tym mieszanie / dopasowanie kodu skompilowanego z innym jest całkowicie fałszywe -fcall-used-reg. Nie ma żadnej __attribute__wersji, która pozwalałaby nam zadeklarować funkcje asm z niestandardowymi konwencjami wywoływania innymi niż zwykle.

#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);
}

Dwie inne wersje również miały 13 bajtów: ta oparta na loopnewartości zwraca wartość zbyt wysoką o 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

Ta wersja używa rep scasd zamiast pętli, ale pobiera modulo 256 zliczania argów (lub ograniczona do 256, jeśli górne bajty ecxsą 0 przy wejściu!)

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

Zabawne jest, że kolejna wersja oparta na inc eax/ pop edx/ test edx,edx/ jnzma 13 bajtów. Jest to konwencja callee-pops, która nigdy nie jest wykorzystywana przez implementacje języka C do funkcji variadic. (Wstawiłem add add do ecx, a jmp ecx zamiast ret. (Lub push / ret, aby nie zepsuć stosu predykcji adresu zwrotnego).




Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.