Wie viele Argumente wurden übergeben?


33

Schreiben Sie in der Sprache Ihrer Wahl eine Funktion, die eine variable Anzahl von Argumenten akzeptiert und die Anzahl der Argumente zurückgibt, mit denen sie aufgerufen wurde.

Besonderheiten:

  • Ihre Sprache muss verschiedene Argumentfunktionen unterstützen: Eine aufrufbare Funktion, die eine beliebige Anzahl von Argumenten akzeptiert und einen Wert zurückgibt.
  • Parameter müssen einzeln übergeben werden können. Dies bedeutet, dass das Übergeben eines Arrays nur für einen Parameter zählt. Sie können ein Array "alle übergebenen Argumente" verwenden, wenn Ihre Sprache dies unterstützt. Die Einschränkung besteht darin, wie die Funktion aufgerufen wird.
  • Code, der diese Funktion aufruft, muss nicht erforderlich sein, um die Anzahl der Argumente in seiner Quelle zu übergeben . Wenn ein Compiler die Anzahl der Argumente als Teil einer Aufrufkonvention einfügt, ist dies zulässig.
  • Die Argumente können von einem beliebigen Typ sein. Sie können nur einen einzelnen Typ unterstützen (z. B. ist nur die Unterstützung intnoch gültig), beliebige Typen (jede Art von Argument ist zulässig) oder eine beliebige Kombination von Argumenttypen (z. B. erstes Argument ist int, Rest sind Zeichenfolgen).
  • Ihre Funktion kann eine maximale Anzahl von Argumenten enthalten (insbesondere, da die Ressourcen endlich sind), muss jedoch mindestens 2 Argumente unterstützen.

Proben:

  • f() kehrt zurück 0
  • f(1)oder f("a")kehrt zurück1
  • f([1, 2, 3])Gibt 1beim Übergeben ein Array zurück, nicht 3 Argumente
  • f(1, 10)oder f(1, "a")kehrt zurück2

Da dies Codegolf ist, ist die gewinnbringende Lösung diejenige, die die geringste Anzahl von Bytes verwendet.


4
Es ist nicht ganz klar (objektiv), was eine "Funktion", ein "Rückgabewert" oder "verschiedene Argumente" sind. Würde zum Beispiel die Dodos-Funktion als monadisch oder variadisch betrachtet?
user202729

24
@ user202729 Wenn Ihre Sprache keine Funktionen unterstützt, verwenden Sie eine andere Sprache. Es ist nicht unbedingt erforderlich, dass alle Sprachen mithalten können. Zum Code-Golfen gehört es, das richtige Werkzeug für den Job zu finden.
Sanchises

5
@ user202729 Ich habe keine Probleme mit der gelegentlichen Herausforderung, die sich an traditionelle / Hochsprachen richtet, genauso wie wir die gelegentliche Herausforderung haben, die nur in ungewöhnlichen Sprachen möglich ist.
Sanchises

6
Ich wusste nicht, dass wir das Stopp-Problem lösen müssen, damit die Sprachmerkmale eine klare Herausforderung darstellen ...
Conor O'Brien

5
Wenn Ihre Sprache nicht über das Konzept der Argumente / Aufrufkonvention verfügt, entspricht sie nicht den Kriterien für die Unterstützung einer beliebigen Anzahl von Argumenten.
Glenn Smith

Antworten:


15

Amstrad CPC Z80-Binäraufruf von BASIC, 1 Byte, hexadezimal codiert

C9          : RET

(Auch 2- und 5-Byte-Versionen, siehe unten)

Bei der Eingabe zum Aufruf wird die Anzahl der übergebenen Parameter im ARegister gespeichert. Der Code kehrt einfach sofort zurück. Es gibt kein Konzept für Rückgabewerte im Z80, nur für Ein- und Ausstiegszustände. Auf den Wert kann nur "dort" im Register zugegriffen werden, da der Code bis auf PC(den Programmzähler) und SP(den Stapelzeiger) keine Eingabebedingungen ändert . Der Wert in Aist jedoch für BASIC nicht zugänglich und wird fast sofort überschrieben.

Beispiele:

CALL &8000, "Hello", "World"

A = 2

CALL &8000, 42

A = 1

CALL &8000

A = 0


Auf Anfrage finden Sie hier einen Code, der den Wert in BASIC zugänglich macht. Ich war sehr überrascht, dass dies in nur 5 Bytes möglich war !:

Der Maschinencode:

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

Bei der Einreise:

  • AF - die Akkumulator- und Merkerregister (behandelt als zwei 8-Bit-Register)
    • A enthält die Anzahl der übergebenen Parameter bis zu maximal 32 Parametern
    • Ich bin nicht sicher, was drin ist F. Es scheinen alle Flags auf RESET zu sein 0, mit Ausnahme der beiden undefinierten Flags, die beide sind 1. Das ZFlag (Null) wird auf gesetzt, 1wenn keine Parameter übergeben wurden
  • BC
    • B- 32 minus die Anzahl der Parameter ( A+ B= 32)
    • C - &FF
  • DE - Die Adresse des letzten Parameters oder die aufrufende Adresse, wenn keine Parameter übergeben wurden
  • HL - Die Adresse des ersten Bytes nach dem aktuell ausgeführten tokenisierten BASIC-Befehl (entweder als Programm oder im Sofortbefehlsmodus)
  • IX - Die Stapeladresse des Zeigers auf den letzten Parameter
  • IY - &0000

Der Code

  1. Loa Ds die Adresse, auf die von DEmit dem Wert in verwiesen wirdA
  2. INCrements DE
  3. XORs A(mit A) geben&00
  4. Loa Ds der Wert in Ader Adresse, auf die von verwiesen wirdDE
  5. RETUrnen

Bei der Ausfahrt:

  • Aist zerstört (es ist immer &00)
  • DE ist zerstört (es ist immer eine höher als bei der Einreise)
  • Alle anderen Register bleiben erhalten

Das BASIC

Amstrad Basic hat nur drei Datentypen sowie einfache Arrays. Standardmäßig sind alle BASIC-Variablen REAL (vorzeichenbehaftet, 32-Bit-Mantisse, 8-Bit-Exponent), was mit explizit angegeben werden kann !. Verwenden Sie %für eine INTEGER- Zeichenfolge (mit Vorzeichen, 16 Bit) und für eine STRING-Zeichenfolge (1 Byte Zeichenfolgenlänge, bis zu 255 Byte Zeichendaten, binär sicher) Folgendes $:

  • x - REAL (implizit)
  • x! - REAL (explizit)
  • x% - INTEGER
  • x$ - STRING

Sie können auch verwendet werden DEFINT, DEFREALund DEFSTRmit einem einzigen Buchstaben oder einer Reihe von zwei einzelnen Buchstaben den Standardtyp für alle Variablen mit diesem Buchstaben, ähnlich wie Fortran angeben , beginnend mit .

  • DEFSTR a
  • DEFINT x-z

Jetzt:

  • a - STRING (implizit)
  • i - REAL (implizit)
  • x - INTEGER (implizit)
  • x$ - STRING (explizit)

Am einfachsten ist es, mit der Ganzzahl zu arbeiten. Der Maschinencode erwartet, dass der letzte Parameter als Adresse und nicht als Wert übergeben wird, weshalb @der Variablen ein Präfix vorangestellt wird. Die Rückgabevariable wird als einer der CALLs-Parameter gezählt.

Der Maschinencode wird von BASIC wie folgt aufgerufen (vorausgesetzt, er wird an der Adresse in den Speicher geladen &8000):

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

n% = 4

Dies liefert immer das richtige Ergebnis, unabhängig vom Anfangswert von n%.

Für eine 2-Byte-Version, bei der alle Eingaberegister erhalten bleiben:

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

n% = 4

Damit springt die ersten drei Bytes und gibt nur das richtige Ergebnis , wenn der Anfangswert n%ist 0- 255. Dies funktioniert, weil der Z80 Little-Endian ist.

Der Rückgabeparameter muss vor der Übergabe initialisiert werden, andernfalls gibt BASIC einen Improper argumentFehler aus. Im folgenden Bild ?drucke ich (mit der Verknüpfung, seitdem ich die Demonstration auch gespielt habe!) Die Rückgabewerte unmittelbar vor und nach dem Aufruf, um die Wertänderung anzuzeigen. Ich verwende den Wert, &FFFFweil dies die binäre Darstellung -1für eine Ganzzahl mit Vorzeichen ist. Dies zeigt, dass das 5-Byte-Programm beide Bytes korrekt schreibt, während das 2-Byte-Programm nur das niedrige Byte schreibt und davon ausgeht, dass das hohe Byte bereits vorhanden ist &00.

Bildbeschreibung hier eingeben


Wie funktioniert die aufrufende Konvention, die Sie Rückgabewerte verwenden? Wenn sie nicht oder überhaupt nicht in den Akkumulator zurückgegeben werden, besteht Ihre Antwort darin, eine benutzerdefinierte Aufrufkonvention zu erfinden, die das Problem für Sie löst (indem Sie ein Rückgaberegister hinzufügen, anstatt einen Zeiger zu übergeben, in dem Sie speichern können A, falls dies der Fall ist wie könnte man das eigentlich aus BASIC machen). Nicht, dass daran etwas falsch ist, aber es könnte eine interessantere Antwort sein, einer bestehenden Calliing-Konvention zu folgen.
Peter Cordes

@PeterCordes Weder Amstrad BASIC noch das Z80 haben das Konzept von Gültigkeitsbereichen. Alle Werte sind global und bis zur Zerstörung sofort verfügbar. Der Wert von Aist gleich unmittelbar nach der RETAnweisung. Die Lebensdauer eines Wertes in Aist sehr kurz, da es sich um den Akkumulator handelt. So etwas gibt es nicht x = CALL &8000, 42. Es müsste sein CALL &8000, x, 42, und zusätzlicher Z80-Code, aber dann xwäre es 2nicht 1.
CJ Dennis

Ich denke, es ist in Ordnung, wenn Sie das Ausgabearg in die Zählung einbeziehen, andernfalls gibt es eine 1-Byte-Dekrementierungsanweisung, nicht wahr? Es würde mich interessieren, eine Version zu sehen, die tatsächlich von BASIC aus verwendet werden kann, anstatt trivial zu sein.
Peter Cordes

1
@PeterCordes Fertig! Oh, übrigens, ich habe vergessen zu erwähnen, es nicht ohne Parameter aufzurufen, da es seine eigenen ersten beiden Anweisungen mit &00s - NOPno-ops überschreibt . Ein weiteres Byte kann hinzugefügt werden, um die Sicherheit zu erhöhen. Ohne einen Rückgabeparameter kann jedoch nichts festgelegt werden.
CJ Dennis

32

Java (JDK 10) , 11 Byte

a->a.length

Probieren Sie es online!


29
Java schlagen Javscript ist selten genug, um bemerkt zu werden
Der zufällige Kerl

3
@Therandomguy Dazu muss so etwas wie interface x{void f(Object...a);}definiert werden, und dieses Lambda muss entweder in einer Variablen dieses Schnittstellentyps gespeichert oder an eine Methode übergeben werden, die diesen Schnittstellentyp erwartet obwohl in der Regel Java Lambdas in Codegolf-Herausforderungen erlaubt sind)
SamYonnou

3
@ SamYonnou Es gibt keinen Unterschied zu anderen Lambdas, und wie Sie bereits erwähnt haben, sind Lambdas in Ordnung .
Olivier Grégoire

@ OlivierGrégoire Ich weiß, dass Lambdas erlaubt sind. Mein Punkt war, dass Sie im Vergleich zu JavaScript zum Beispiel viel mehr zusätzlichen Code benötigen, um es einzurichten, auch wenn Sie so etwas wie REPL verwenden und die Notwendigkeit einer Hauptklasse / -methode vermeiden ( Die Notwendigkeit, die Schnittstelle zu definieren, ist das, was sie von JavaScript unterscheidet.
SamYonnou

@ OlivierGrégoire: Ich kenne etwas Java, habe es aber überhaupt nicht mitbekommen. Ich war daran interessiert, Sams Kommentar darüber zu sehen, was Boilerplate in einer Java-Antwort unter den Teppich gekehrt wird, die es tatsächlich sehr kurz macht. Ich bin damit einverstanden, dass es erlaubt sein sollte (obwohl es Ihnen etwas gibt, das Sie normalerweise nicht mit Java-Funktionen bekommen, richtig, es ist also nicht nur eine Reduzierung des Boilerplates, sondern es gibt Ihnen ein eingebautes Arg-Counting). Außerdem ist es als Antwort auf "Java beating JS" immer noch interessant.
Peter Cordes

25

JavaScript, 15 Byte

[].push.bind(0)

Die Array.prototype.pushFunktion akzeptiert eine beliebige Anzahl von Argumenten, fügt sie ihrem Array hinzu und gibt die Größe des Arrays zurück. Daher gibt die pushin einem leeren Array verwendete Funktion die Anzahl der Argumente zurück, die übergeben wurden push.

f = [].push.bind(0)

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

f()
> 0

Das .bind(0)gibt der pushFunktion einfach einen festen thisWert, damit sie in einer Variablen gespeichert werden kann. Tatsächlich kann der 7-Byte-Bezeichner [].pushwörtlich verwendet (aber nicht zugewiesen) werden, ohne bind:

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

[].push()
> 0


18

Haskell , 108 107 95 94 Bytes

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

Probieren Sie es online!

Es war überraschend schwierig, damit umzugehen, aber ich hatte Spaß daran, herauszufinden, wie man etwas Triviales in imperativen Sprachen umsetzt.


Verdammt, du hast mich geschlagen. fist optional wenn du sagst z 0ist die funktion ohne bindung, main = print $ ((z 0) pi 0 () [] :: Int)funktioniert also.
Angs

Und damit meine ich, dass die Typen funktionieren, wenn sie als anonyme Funktion verwendet werden, sodass Sie in der Tat alles aus den letzten beiden Zeilen entfernen können, außerz 0
Angs

Nett, danke! Es stellte sich heraus, dass ich beim Testen der anonymen Funktion etwas falsch gemacht habe. Versuchte dein Beispiel und es hat gut funktioniert.
user9549915

Ich denke, das ::Intsollte in der Byteanzahl gezählt werden, da der Typ der Antwort früher oder später wie in deklariert werden muss main = print $ ((z 0 :: Double -> Integer -> () -> [a] -> (Int->Int->Int) -> IO () -> Int) pi 0 () [] (+) main). Ich denke auch, dass dies nur während der Kompilierungszeit funktioniert, so etwas foldl(\a b->a b) (z 0) $ [1..5])::Intkann nicht funktionieren. So oder so, das ist großartiges Zeug.
Angs

2
s/imperative/non-curry/
user202729


12

Zsh , 7 5 Bytes

<<<$#

Probieren Sie es online!


Obwohl es wahrscheinlich verpackt werden sollte:f(){ echo $#; }
muru

8
@muru Das sieht für mich gut aus als volles Programm.
Neil

Obwohl ich jetzt sehe, dass das OP nur eine Funktion will ...
Neil

2
@ Neil-Shell-Skripte verhalten sich genauso wie Funktionen. OP ist nicht klar, was eine Funktion ist, ich behaupte, meine Einreichung ist nur eine Funktion, die auf der Festplatte gespeichert ist.
Pavel

9

Brain-Flak , 6 Bytes

Meine erste Brain-Flak-Lösung, die es wert ist, veröffentlicht zu werden. Ich denke, sie ist das richtige Werkzeug für diesen Job:

([]<>)

Probieren Sie es online!

Erläuterung

Bei der Ausführung eines Brain-Flak-Programms enthält der linke Stapel zunächst alle Argumente. Von dort ist es einfach eine Frage von:

(      -- 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 Bytes

Tr[1^{##}]&

Probieren Sie es online!

Vorgeschlagen von JungHwan Einige Einschränkungen (Eingaben müssen rechteckig sein), aber wir müssen keine willkürlichen Eingaben verarbeiten.

11 Bytes

Length@!##&

Probieren Sie es online!

Eine weitere 11-Byte-Lösung von Martin Ender. Dies scheint ein Fehler zu sein, wenn es keinen Eingang gibt, der aber in allen Fällen den korrekten Wert zurückgibt.

12 Bytes

Length@{##}&

Probieren Sie es online!

Meine ursprüngliche Lösung.

In Mathematica ##steht für eine unterschiedliche Anzahl von Argumenten in einer Funktion. {und }packt sie in eine Liste und Length@nimmt die Länge dieser Liste. &am Ende verwandelt sich dies in eine tatsächliche Funktion.


7

R , 30 Bytes

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

Probieren Sie es online!


1
function(...)nargs()ist 20 Bytes, aber mit length(...)war mein erster Ansatz, bis ich eine nargsähnliche Funktion googelte .
Giuseppe

@ Giuseppe hmm, ich habe versucht, das list(...)in ein logisches zu konvertieren , damit sum()es verwendet werden kann, aber das ist schwierig: /
JAD

1
Haha, versuchen Sie nicht, mich für dieses Argument zu
begeistern

1
@RoryT oh eigentlich sagen R docs kombinieren. Nevermind: D
JAD

2
...length() macht das gleiche wielength(list(...))
Giuseppe

7

Bash, 12 Bytes (danke an paxdiablo für das Speichern von 4)

n()(echo $#)

Kopieren und einfügen an einer Bash-Eingabeaufforderung. Führen Sie dann die Funktion n an der Eingabeaufforderung aus:

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

2
Willkommen bei PPCG!
Martin Ender

Kannst du einfach sagen, es ist ein Skript "./n" und keine Funktion? dann sind es nur noch echo $#:, 7 bytes. (wird dann jede Shell Sie verwenden , um die „./n“ Skript starten mit dh Sie bash laufen dann , wenn Sie:.? ./n arg1 ... argnes von bash interpretiert wird.)
Olivier Dulac

@Olivier Dulac Die Herausforderung sagt eindeutig eine Funktion aus.
Wastrel

7

C ++ 14 (gcc) , 34 Bytes

Als generische variadische Lambda-Funktion (C ++ 14 erforderlich):

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

Probieren Sie es online!

Vorherige (falsche) Antwort: 32 Bytes

Es fehlte das template<class...T>und(p)

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

6
C ++ 14, C ++ 11 hat keine generischen Lambdas.
Quentin

1
Sie können das zulässige Flag hinzufügen, um die Klammern zu entfernenp (und -wdie Warnung auszuschalten).
NWP

@nwp: Würden -fpermissiveSie die 12 Bytes für diese Option nicht kosten? Wenn es nicht Standard ISO C ++ oder GNU C ++ ist.
Peter Cordes

@PeterCordes Dies ist wahrscheinlich der Fall, und es soll vermieden werden, dass eine einfache 0-Byte-Lösung für alles vorhanden ist, indem das Programm über die Befehlszeile übergeben wird. Ich habe hier nur nicht darüber nachgedacht, weil es nicht missbräuchlich zu sein scheint.
NWP

@Quentin behoben -> C ++ 14
Bierpfurz


5

Oktave , 9 Bytes

@()nargin

Probieren Sie es online!

Anonyme Funktion, die eine beliebige Anzahl von Argumenten annimmt (und das Los stillschweigend verwirft) und die Anzahl der Argumente über die integrierte Funktion ausgibt nargin. Dies funktioniert nicht in MATLAB, wo Sie vararginbeliebig viele Argumente zulassen müssten .



4

Perl 5 , 9 Bytes

sub{~~@_}

Probieren Sie es online!


Eine schnelle, umfassende Suche nach Antworten scheint darauf hinzudeuten, dass Sie dassub
Nur-ASCII-

2
Protip: Mit TIO können Sie im PPCG-Post-Format (ESC, S, G) kopieren
ASCII

@ Nur ASCII Oh schön, danke! :) Was das Auslassen angeht sub, denke ich nicht. Es ist keine Funktion ohne sie.
Chris

@ Nur ASCII Ich würde Antworten ohne subungültig betrachten, da das Ergebnis nicht aufgerufen oder einer Variablen zugewiesen werden kann
Ton Hospel


4

C # .NET, 11 Bytes

a=>a.Length

Probieren Sie es online aus.

Erläuterung:

In C # wird .NET objectfür Argumente mit mehreren Typen verwendet, sodass Ganzzahlen, Zeichenfolgen, Zeichen usw. als mögliche Eingaben übergeben werden können. Beispielsweise:

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

C # .NET kann auch eine feste Größe optionaler Argumente haben. Beispielsweise:

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

Und es gibt auch varargs, eine undefinierte Menge optionaler Argumente (was ich in dieser Antwort verwendet habe). Beispielsweise:

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

Normalerweise werden Lambdas wie folgt erstellt:

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)

Aber leider System.Funcunterstützt paramsvarargs nicht, daher muss delegatestattdessen ein erstellt werden:

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

Welches ist meine Antwort auf diese Herausforderung und kann im verknüpften TIO-Testcode gefunden werden.


Die einzige Einschränkung ist , dass eine tatsächliche Eingabe object[]wie f(new object[]{1,2,3})in 3 führt statt 1 f(new int[]{1,2,3})wird immer noch zu 1, weil es die interpretiert int[]als eine einzigeobject . Damit das object[]werden Parameter als ein einzelnes Objekt zu interpretieren und kann es auf ein Objekt wie diese gegossen werden: f((object)new object[]{1,2,3}).


Ich muss sagen, wenn es jemals eine Antwort gäbe, die mich dazu brachte, Lambda-bezogene Boilerplate in C # -Antworten zu unterstützen, wäre es diese ... aber es ist definitiv eine gültige Lösung.
Kamil Drakari

@KamilDrakari Vielleicht war es in der Tat nicht ganz klar, was ich getan habe, ohne den TIO-Link zu öffnen, also habe ich eine Erklärung hinzugefügt.
Kevin Cruijssen

1
@Taemyr Ich habe versucht , eine Lösung zu finden, aber leider gibt es keine für C # .NET, mit Ausnahme Giessharzsystemen object[]Parameter object, wie folgt aus : f((object)new object[]{1,2,3});. Es gibt keine Möglichkeit, zwischen f(new object[]{1,2,3});und f(1,2,3);so weit zu unterscheiden, wie ich es finden konnte.
Kevin Cruijssen

1
Dies behandelt die Array-Parameter korrekt für eine große Anzahl von Bytes. Es könnte eine präzisere Struktur geben, die damit umgehen kann, aber sie funktioniert in meinen Tests.
Kamil Drakari

1
@KamilDrakari Hmm, aber es schlägt f(1, new object[]{1,2,3})erneut fehl . Nicht sicher, ob eine Lösung für dieses Verhalten gefunden werden kann.
Kevin Cruijssen

4

Dodos , 32 31 Bytes

f
	dot i f dab
i
	
	dip dot dab

Probieren Sie es online!

Verwendet Dennis 'Inkrementfunktion.

Erläuterung

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

Alternativ 32 Bytes ohne Rekursion in der Zielfunktion (danke @Leo )

	dot i
i
	dip dot dab dot
	i dab

Probieren Sie es online!

Erläuterung

        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)

Hier ist eine weitere Lösung gleicher Länge. Probieren Sie es online aus! Ich kann anscheinend nicht verstehen, warum deins funktioniert. Könnten Sie bitte eine Erklärung hinzufügen?
Leo

Hey, du hast meiner Lösung eine Erklärung hinzugefügt! Ich wollte eine für Sie, ich weiß, wie meins funktioniert xD
Leo

1
@Leo Entschuldigung für die verspätete Antwort, idek, was ich tue, kopiert nur Dennis 'Funktion, wird versuchen, so schnell wie möglich zu verstehen. Ich hatte keine Ahnung, wie Dodos funktioniert, also habe ich herausgefunden, was Ihre zuerst gemacht haben
ASCII

Keine Sorge, es war nur eine lustige Situation :)
Leo

@Leo ok also macht meine erklärung sinn? (Anmerkung: Ich bin auf dem Handy, also zögern Sie nicht, es zu bearbeiten, um es besser zu machen, lol)
Nur ASCII

3

C ++, 72 Bytes

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

Spart Bytes, indem nur mit ints gearbeitet wird.


Sie können verwenden sizeof....
LF

3

Rust, 57 Bytes

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

Erläuterung:

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.
    };
}

Prüfung:

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;

Probieren Sie es online aus: 1 Eingang | 3 Eingänge


Ich bin mir da nicht so sicher (und es ist gültig), da es sich um die Anzahl der Argumente handelt, die an den Aufruf von PHP übergeben wurden.
Ismael Miguel

@IsmaelMiguel, siehe diesen Konsens .
Shaggy

1
Die Frage erfordert explizit eine Funktion , die die Nummer zurückgibt , sie jedoch nicht anzeigt: "... schreibe eine Funktion, die eine variable Anzahl von Argumenten annimmt und die Anzahl der Argumente zurückgibt."
Axiac

1
Wiederholen Sie die Frage: "Schreiben Sie in der Sprache Ihrer Wahl eine Funktion , die eine variable Anzahl von Argumenten akzeptiert und die Anzahl der Argumente zurückgibt, mit denen sie aufgerufen wurde." Ihr Code enthält keine Funktionen.
Ismael Miguel

@IsmaelMiguel, wenn das tatsächlich der Fall wäre, würden auch viele andere Lösungen ungültig. Die Norm besteht darin, Lösungen als Programme oder Funktionen zuzulassen.
Shaggy

2

Batch, 50 49 Bytes

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

Kein eingebautes Batch, also müssen wir auf die alte Schule gehen. 1 Byte dank @IsmaelMiguel gespeichert. Ausgabe über Exit-Code oder Speicherung von 3 Bytes, wenn die Ausgabe über die globale Variable gültig ist. Beispiel für die Verwendung in einem vollständigen Programm:

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

Ich glaube, dass diese Antwort gegen die Regeln verstößt. Batch hat etwas in der Nähe von Funktionen. Sie können etwas Ähnliches tun wie :a|set r=0&for %%a in (%*)do set/ar+=1( |= Newline im Windows-Stil). Diese Lösung ist 38 Bytes. Um es auszuführen, mache call :a <args>mit a goto :eofvor der Funktion, was der Wert ist, der in der Variablen verfügbar ist r. Wenn Sie Ihre Lösung behalten möchten, entfernen Sie /adie erste setund entfernen Sie diese @.
Ismael Miguel

Gefällt dir das? (Hinweis: Ich habe den Funktionsnamen nicht in die Byteanzahl eingeschlossen, aber ich habe die Funktionsrückgabe eingeschlossen, was vernünftig erscheint, da es irgendwo eine geben muss.)
Neil,

Ja, genau das ist es. Schöner Fang mit dem Exit-Code! Ich war überrascht zu sehen, dass Exitcodes größer als 255 sein können. Ein Beispiel ist die von Symantec bereitgestellte Liste: symantec.com/connect/articles/…
Ismael Miguel

2

x86-Maschinencodefunktion mit 32 Bit (i386), 13 Byte

Aufrufkonvention: i386 System V (Stapelargumente), mit einem NULL-Zeiger als Sentinel / Terminator für das Ende der Argumentliste . (Clobbers EDI, entspricht sonst SysV).

C (und asm) übergeben keine Typinformationen an verschiedene Funktionen. Daher kann die OP-Beschreibung der Übergabe von Ganzzahlen oder Arrays ohne explizite Typinformationen nur in einer Konvention implementiert werden, die eine Art Struktur- / Klassenobjekt (oder Zeiger auf ein solches Objekt) übergibt ), keine ganzen Zahlen auf dem Stapel. Daher habe ich angenommen, dass alle Argumente Nicht-NULL-Zeiger sind und der Aufrufer ein NULL-Abschlusszeichen übergibt.

Eine NULL-terminierte Zeigerliste von Argumenten wird in C tatsächlich für Funktionen wie POSIX verwendetexecl(3) : int execl(const char *path, const char *arg, ... /* (char *) NULL */);

C erlaubt keine int foo(...);Prototypen ohne festes Argument, int foo();bedeutet aber dasselbe: Argumente, die nicht spezifiziert sind. (Anders als in C ++, wo es bedeutet int foo(void)). In jedem Fall ist dies eine asm Antwort. Einen C-Compiler zu überreden, diese Funktion direkt aufzurufen, ist interessant, aber nicht erforderlich.

nasm -felf32 -l/dev/stdout arg-count.asm Einige Kommentarzeilen wurden entfernt.

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

Die Frage zeigt, dass die Funktion in der Lage sein muss, 0 zurückzugeben, und ich entschied mich, dieser Anforderung zu folgen, indem ich den abschließenden NULL-Zeiger nicht in die Anzahl der Argumente einbezog. Dies kostet jedoch 1 Byte. (Entfernen Sie für die 12-Byte-Version die LEA und kommentieren Sie die scasdäußere Schleife und die xchg, aber nicht die dec edx. Ich habe die LEA verwendet, weil sie die gleichen Kosten wie die anderen drei Anweisungen zusammen verursacht, aber effizienter ist, sodass die Funktion geringer ist.) uops.)

C-Aufrufer zum Testen :

Gebaut mit:

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-ediist sogar bei -O0 erforderlich, um gcc anzuweisen, davon auszugehen, dass Funktionen nicht gespeichert edi/ wiederhergestellt werden, da ich so viele Aufrufe in einer C-Anweisung (dem printfAufruf) verwendet habe, die sogar -O0EDI verwendet hat. Es scheint sicher zu sein main, dass GCCs EDI von ihrem eigenen Aufrufer (im CRT-Code) unter Linux mit glibc blockieren, aber ansonsten ist es völlig falsch, mit verschiedenen kompilierten Codes zu mischen / abzugleichen -fcall-used-reg. Es gibt keine __attribute__Version, mit der wir die asm-Funktionen mit anderen als den üblichen benutzerdefinierten Aufrufkonventionen deklarieren könnten.

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

Zwei andere Versionen kamen ebenfalls mit 13 Bytes an: Diese basiert auf loopneeinem Wert, der um 1 zu hoch ist.

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

Diese Version verwendet rep scasd anstelle einer Schleife, verwendet aber das Argument count modulo 256. (Oder begrenzt auf 256, wenn die oberen Bytes von ecx0 bei der Eingabe sind!)

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

Komisch, noch eine weitere Version basierend auf inc eax/ pop edx/ test edx,edx/ jnzkamen 13 Bytes in an. Es ist eine Callee-Pops-Konvention, die von C-Implementierungen niemals für verschiedene Funktionen verwendet wird. (Ich habe die ret-Adresse in ecx und jmp ecx anstelle von ret eingefügt. (Oder push / ret, um den Prädiktorstapel für die Rücksprungadresse nicht zu unterbrechen.)




Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.