Có bao nhiêu đối số đã được thông qua?


33

Sử dụng ngôn ngữ bạn chọn, viết một hàm có số lượng đối số thay đổi và trả về số lượng đối số mà nó được gọi.

Cụ thể:

  • Ngôn ngữ của bạn cần hỗ trợ các hàm đối số dao động: một cái gì đó có thể gọi được có số lượng đối số tùy ý và trả về một giá trị.
  • Các thông số phải có thể được thông qua cá nhân. Điều này có nghĩa là việc truyền một mảng sẽ chỉ được tính cho một tham số. Bạn có thể sử dụng một mảng "tất cả các đối số được thông qua" nếu ngôn ngữ của bạn hỗ trợ nó; hạn chế là cách gọi hàm.
  • Mã gọi hàm này không được yêu cầu để vượt qua số lượng đối số trong nguồn của nó . Nếu một trình biên dịch chèn số lượng đối số như là một phần của quy ước gọi, điều đó được cho phép.
  • Các đối số có thể là bất kỳ loại bạn muốn. Bạn chỉ có thể hỗ trợ một loại duy nhất (ví dụ: chỉ hỗ trợ intvẫn hợp lệ), các loại tùy ý (bất kỳ loại đối số nào được cho phép) hoặc bất kỳ kết hợp nào của các loại đối số (ví dụ: đối số đầu tiên là int, phần còn lại là chuỗi).
  • Hàm của bạn có thể có số lượng đối số tối đa (đặc biệt là vì tài nguyên là hữu hạn), nhưng phải hỗ trợ ít nhất 2 đối số.

Mẫu:

  • f() trả lại 0
  • f(1)hoặc f("a")trả lại1
  • f([1, 2, 3])trả về 1vì nó được truyền vào một mảng, không phải 3 đối số
  • f(1, 10)hoặc f(1, "a")trả lại2

Vì đây là môn đánh gôn, giải pháp chiến thắng là giải pháp sử dụng số byte ít nhất.


4
Nó không hoàn toàn rõ ràng (khách quan) thế nào là "hàm", "giá trị trả về" hoặc "đối số dao động". Ví dụ, chức năng Dodos sẽ được coi là đơn âm hay dao động?
dùng202729

24
@ user202729 Nếu ngôn ngữ của bạn không hỗ trợ các chức năng, hãy sử dụng ngôn ngữ khác. Đó không phải là một yêu cầu mà tất cả các ngôn ngữ có thể cạnh tranh, một phần của môn đánh gôn mã là tìm ra công cụ phù hợp cho công việc.
Sanchise

5
@ user202729 Tôi không gặp vấn đề gì với thử thách không thường xuyên nhắm vào các ngôn ngữ truyền thống / cấp cao, giống như chúng tôi có những thách thức không thường xuyên chỉ có thể có trong các ngôn ngữ khác thường.
Sanchise

6
không biết chúng tôi đã phải giải quyết vấn đề tạm dừng để các đặc điểm ngôn ngữ có một thách thức rõ ràng ....
Conor O'Brien

5
Nếu ngôn ngữ của bạn không có khái niệm về đối số / quy ước gọi thì nó không phù hợp với tiêu chí hỗ trợ số lượng đối số tùy ý.
Glenn Smith

Câu trả lời:


15

Cuộc gọi nhị phân Amstrad CPC Z80 từ BASIC, 1 byte, hex được mã hóa

C9          : RET

(Ngoài ra phiên bản 2 và 5 byte, xem bên dưới)

Khi vào cuộc gọi, số lượng tham số được truyền sẽ nằm trong thanh Aghi. Mã chỉ đơn giản là trả về ngay lập tức. Không có khái niệm về giá trị trả về trong Z80, chỉ có trạng thái nhập và thoát. Giá trị chỉ là "có" có thể truy cập được trong thanh ghi vì mã thay đổi không có điều kiện đầu vào, ngoại trừ PC(bộ đếm chương trình) và SP(con trỏ ngăn xếp). Tuy nhiên, giá trị trong ABASIC không thể truy cập được và bị ghi đè gần như ngay lập tức.

Ví dụ:

CALL &8000, "Hello", "World"

A = 2

CALL &8000, 42

A = 1

CALL &8000

A = 0


Theo yêu cầu, đây là một số mã làm cho giá trị có thể truy cập được trong BASIC. Tôi đã rất ngạc nhiên khi thấy nó có thể được thực hiện chỉ trong 5 byte!:

Mã máy:

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

Khi nhập cảnh:

  • AF - các thanh ghi tích lũy và cờ (được coi là hai thanh ghi 8 bit)
    • A chứa số lượng tham số được truyền, tối đa 32 tham số
    • Tôi không chắc những gì trong F. Dường như có tất cả các cờ RESET 0, ngoại trừ hai cờ không xác định là cả hai 1. Các Zlá cờ (zero) là SET để 1nếu không có các thông số thông qua năm
  • BC
    • B- 32 trừ đi số lượng tham số ( A+ B= 32)
    • C - &FF
  • DE - Địa chỉ của tham số cuối hoặc địa chỉ gọi nếu không có tham số nào được truyền vào
  • HL - Địa chỉ của byte đầu tiên sau lệnh BASIC được mã hóa hiện đang được thực thi (dưới dạng chương trình hoặc ở chế độ lệnh ngay lập tức)
  • IX - Địa chỉ ngăn xếp của con trỏ đến tham số cuối cùng
  • IY - &0000

Mật mã

  1. Loa Ds địa chỉ được chỉ đến bởi DEgiá trị trongA
  2. INCkhẩu vị DE
  3. XORs A(với A), cho&00
  4. Loa Ds giá trị trong Ađịa chỉ được chỉ bởiDE
  5. RETbình

Khi thoát:

  • Abị phá hủy (nó luôn luôn &00)
  • DE bị phá hủy (nó luôn luôn cao hơn so với khi nhập cảnh)
  • Tất cả các thanh ghi khác được bảo quản

Cơ bản

Amstrad cơ bản chỉ có ba loại dữ liệu, cộng với các mảng đơn giản. Theo mặc định, tất cả các biến BASIC là REAL (đã ký, mantissa 32 bit, số mũ 8 bit), có thể được làm rõ ràng với !. Đối với việc sử dụng INTEGER (đã ký, 16 bit) %và cho STRING (độ dài chuỗi 1 byte, tối đa 255 byte dữ liệu ký tự, an toàn nhị phân) sử dụng $:

  • x - THỰC SỰ (ngầm)
  • x! - THẬT (rõ ràng)
  • x% - TỔNG HỢP
  • x$ - CHUỖI

Bạn cũng có thể sử dụng DEFINT, DEFREALDEFSTRvới một lá thư duy nhất, hoặc một loạt các hai chữ duy nhất để xác định loại mặc định cho tất cả các biến bắt đầu bằng chữ đó, tương tự như FORTRAN.

  • DEFSTR a
  • DEFINT x-z

Hiện nay:

  • a - CHUINGI (ngầm)
  • i - THỰC SỰ (ngầm)
  • x - INTEGER (ẩn)
  • x$ - CHUINGI (rõ ràng)

Loại dễ nhất để làm việc là số nguyên. Mã máy hy vọng tham số cuối cùng được truyền theo địa chỉ, không phải giá trị, đó là lý do tại sao @tiền tố của biến. Biến trả về được tính là một trong các CALLtham số s.

Mã máy được gọi như sau từ BASIC (giả sử nó được tải vào bộ nhớ tại địa chỉ &8000):

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

n% = 4

Điều này sẽ luôn cho kết quả chính xác, bất kể giá trị ban đầu là n%.

Đối với phiên bản 2 byte bảo tồn tất cả các thanh ghi đầu vào:

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

n% = 4

Điều này bỏ qua ba byte đầu tiên và chỉ cho kết quả chính xác nếu giá trị ban đầu n%0- 255. Điều này hoạt động vì Z80 là ít endian.

Tham số trả về phải được khởi tạo trước khi được thông qua, nếu không BASIC sẽ đưa ra Improper argumentlỗi. Trong hình ảnh bên dưới, tôi đang in (với phím tắt ?vì tôi cũng đã trình diễn bản trình diễn!) Các giá trị trả về ngay trước và sau lệnh gọi để hiển thị giá trị thay đổi. Tôi đang sử dụng giá trị &FFFFvì đó là biểu diễn nhị phân của -1một số nguyên đã ký. Điều này chứng tỏ rằng chương trình 5 byte ghi chính xác cả hai byte, trong khi chương trình 2 byte chỉ ghi byte thấp và giả sử rằng byte cao đã có sẵn &00.

nhập mô tả hình ảnh ở đây


Vậy làm thế nào để quy ước gọi bạn đang sử dụng các giá trị trả về? Nếu nó không trả lại chúng trong bộ tích lũy, hoặc câu trả lời của bạn về cơ bản là phát minh ra một quy ước gọi tùy chỉnh để giải quyết vấn đề cho bạn (bằng cách thêm một thanh ghi trả lại, thay vì chuyển một con trỏ nơi bạn có thể lưu trữ A, nếu đó là làm thế nào bạn thực sự có thể làm điều đó từ BASIC). Không có gì sai với điều đó, nhưng nó có thể là một câu trả lời thú vị hơn để tuân theo một quy ước gọi vốn hiện có.
Peter Cordes

@PeterCordes Cả Amstrad BASIC và Z80 đều không có khái niệm về phạm vi. Tất cả các giá trị là toàn cầu và có thể truy cập ngay lập tức cho đến khi bị phá hủy. Giá trị của Alà như nhau ngay sau khi REThướng dẫn. Tuổi thọ của một giá trị Arất ngắn vì nó là bộ tích lũy. Không có những thứ như x = CALL &8000, 42. Nó sẽ phải là CALL &8000, x, 42, và mã Z80 bổ sung, nhưng sau đó xsẽ 2không 1.
CJ Dennis

Tôi nghĩ sẽ ổn nếu bạn bao gồm đầu ra arg trong số đếm, nếu không thì có một lệnh giảm 1 byte không có ở đó? Tôi muốn thấy một phiên bản thực sự có thể sử dụng được từ BASIC thay vì tầm thường.
Peter Cordes

1
@PeterCordes Xong! Ồ, nhân tiện, tôi đã quên đề cập đến việc không gọi nó mà không có tham số vì nó sẽ ghi đè lên hai hướng dẫn đầu tiên của chính nó bằng &00s - NOPno-ops. Một byte khác có thể được thêm vào để làm cho nó an toàn hơn, nhưng tất nhiên không có tham số trả về, nó không thể đặt bất cứ thứ gì.
CJ Dennis

32

29
Java đánh bại Javscript rất hiếm khi được chú ý
chàng ngẫu nhiên

3
@Therandomguy điều này đòi hỏi một cái gì đó giống như interface x{void f(Object...a);}được xác định và lambda này phải được lưu trữ trong một biến của loại giao diện đó hoặc được chuyển đến một phương thức mong đợi loại giao diện đó, vì vậy tôi không thực sự chắc chắn rằng nó được tính cho thử thách này (thậm chí mặc dù thông thường java lambdas được cho phép trong các thử thách codegolf)
SamYonnou

3
@SamYonnou Không có sự khác biệt với các lambdas khác, và như bạn đã đề cập, lambdas là tốt .
Olivier Grégoire

@ OlivierGrégoire Tôi biết rằng lambdas được cho phép, quan điểm của tôi là so với JavaScript chẳng hạn, bạn cần thêm nhiều mã để thiết lập nó, ngay cả khi bạn đang sử dụng một cái gì đó như REPL và tránh sự cần thiết của một lớp / phương thức chính ( sự cần thiết phải xác định giao diện là những gì phân biệt nó với JavaScript)
SamYonnou

@ OlivierGrégoire: Tôi biết một số Java nhưng không theo kịp với nó. Tôi rất thích xem bình luận của Sam về cái nồi hơi đang bị cuốn theo tấm thảm trong câu trả lời Java cho phép nó thực sự ngắn. Tôi đồng ý rằng nó nên được cho phép (mặc dù nó mang lại cho bạn thứ gì đó mà bạn không thường có với các hàm Java, vì vậy, nó không chỉ là giảm tốc độ mà còn mang lại cho bạn tính năng tích hợp tính toán). Bên cạnh đó, nó vẫn thú vị khi trả lời "Java đập JS".
Peter Cordes

25

JavaScript, 15 byte

[].push.bind(0)

Các Array.prototype.pushchức năng phải mất bất kỳ số lượng đối số, thêm chúng vào mảng của nó, và trả về kích thước của mảng. Do đó, pushhàm được sử dụng trên một mảng trống trả về số lượng đối số được cung cấp cho push.

f = [].push.bind(0)

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

f()
> 0

Đơn .bind(0)giản chỉ cần cung cấp cho pushhàm một thisgiá trị cố định để nó có thể được lưu trữ trong một biến. Trong thực tế, định danh 7 byte [].pushcó thể được sử dụng theo nghĩa đen (nhưng không được chỉ định) mà không có bind:

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

[].push()
> 0


18

Haskell , 108 107 95 94 byte

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

Hãy thử trực tuyến!

Điều này thật khó để làm việc một cách đáng ngạc nhiên, nhưng tôi đã rất vui khi cố gắng tìm ra cách thực hiện một cái gì đó tầm thường trong các ngôn ngữ mệnh lệnh.


Chết tiệt, bạn đánh tôi với nó. flà tùy chọn nếu bạn nói z 0là hàm không có ràng buộc, vì vậy main = print $ ((z 0) pi 0 () [] :: Int)hoạt động.
Angs

Và điều đó có nghĩa là các loại hoạt động khi được sử dụng như một hàm ẩn danh để bạn thực sự có thể xóa mọi thứ khỏi hai hàng cuối trừz 0
Angs

Rất vui, cảm ơn! Hóa ra tôi đã làm gì đó sai khi tôi đang kiểm tra chức năng ẩn danh. Đã thử ví dụ của bạn và nó hoạt động tốt.
dùng9549915

Tôi đoán ::Intnên được tính trong số byte, vì loại câu trả lời phải được khai báo sớm hay muộn, như trong main = print $ ((z 0 :: Double -> Integer -> () -> [a] -> (Int->Int->Int) -> IO () -> Int) pi 0 () [] (+) main). Tôi cũng nghĩ rằng điều này chỉ hoạt động trong thời gian biên dịch nên một cái gì đó như foldl(\a b->a b) (z 0) $ [1..5])::Intkhông thể làm việc. Dù bằng cách nào, đây là công cụ tuyệt vời.
Angs

2
s/imperative/non-curry/
dùng202729


12

Zsh , 7 5 byte

<<<$#

Hãy thử trực tuyến!


Mặc dù có lẽ nên gói lại:f(){ echo $#; }
muru

8
@muru Điều đó có vẻ tốt như một chương trình đầy đủ với tôi.
Neil

Mặc dù, tôi thấy rằng OP chỉ muốn một chức năng ...
Neil

2
Các kịch bản shell @Neil hoạt động chính xác như các hàm. OP không rõ chức năng là gì, tôi khẳng định trình của tôi chỉ là một chức năng được lưu vào đĩa.
Pavel

9

Brain-Flak , 6 byte

Giải pháp Brain-Flak đầu tiên của tôi đáng đăng, tôi đoán đó là công cụ phù hợp cho công việc này:

([]<>)

Hãy thử trực tuyến!

Giải trình

Khi thực hiện chương trình Brain-Flak, ban đầu ngăn xếp bên trái chứa tất cả các đối số. Từ đó đơn giản chỉ là vấn đề:

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

Ngôn ngữ Wolfram (Mathicala) , 11 byte

Tr[1^{##}]&

Hãy thử trực tuyến!

Được đề xuất bởi JungHwan Min. Một số hạn chế (đầu vào phải là hình chữ nhật) nhưng chúng tôi không bắt buộc phải xử lý đầu vào tùy ý.

11 byte

Length@!##&

Hãy thử trực tuyến!

Một giải pháp 11 byte khác được đề xuất bởi Martin Ender. Điều này có vẻ như lỗi khi không có một đầu vào nhưng nó vẫn trả về giá trị chính xác trong mọi trường hợp.

12 byte

Length@{##}&

Hãy thử trực tuyến!

Giải pháp ban đầu của tôi.

Trong Mathicala ##là viết tắt của một số lượng đối số dao động trong một hàm. {}kết thúc chúng trong một danh sách và Length@lấy độ dài của danh sách này. &ở cuối biến điều này thành một chức năng thực tế.


7

R , 30 byte

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

Hãy thử trực tuyến!


1
function(...)nargs()là 20 byte, nhưng sử dụng length(...)là cách tiếp cận ban đầu của tôi cho đến khi tôi tìm được một nargschức năng giống như.
Giuseppe

@Giuseppe hmm, tôi đã thử chuyển đổi thành list(...)logic để sum()có thể sử dụng, nhưng điều đó thật khó khăn: /
JAD

1
Haha, đừng thử và dụ tôi vào cuộc tranh luận đó;)
RoryT

1
@RoryT oh thực sự, R docs nói kết hợp. Nevermind: D
JAD

2
...length() làm điều tương tự nhưlength(list(...))
Giuseppe

7

Bash, 12 byte (nhờ paxdiablo để lưu 4)

n()(echo $#)

Sao chép và dán tại một dấu nhắc bash. Sau đó chạy hàm n từ dấu nhắc:

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

2
Chào mừng đến với PPCG!
Martin Ender

bạn có thể nói đó là tập lệnh "./n" chứ không phải hàm không? thì nó chỉ là : echo $#, 7 byte. (sau đó sẽ là bất kỳ shell nào bạn sử dụng để khởi chạy tập lệnh "./n" với. tức là bạn chạy bash? sau đó khi bạn: ./n arg1 ... argnnó sẽ được giải thích bằng bash.)
Olivier Dulac

@Olivier Dulac Thử thách nói rõ một chức năng.
Wastrel

7

C ++ 14 (gcc) , 34 byte

Là hàm lambda chung (yêu cầu C ++ 14):

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

Hãy thử trực tuyến!

Câu trả lời trước (không chính xác): 32 byte

Nó đã thiếu template<class...T>(p)

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

6
C ++ 14, C ++ 11 không có lambdas chung.
Quentin


@nwp: Tuy nhiên, bạn sẽ không -fpermissivemất 12 byte cho tùy chọn đó chứ? Nếu nó không phải là tiêu chuẩn ISO C ++ hoặc GNU C ++.
Peter Cordes

@PeterCordes Có lẽ nó có và dự định tránh có một giải pháp 0 byte tầm thường cho mọi thứ bằng cách chuyển chương trình qua dòng lệnh. Tôi chỉ không nghĩ về điều đó ở đây vì nó dường như không bị lạm dụng.
nwp

@Quentin đã sửa -> C ++ 14
Bierpfurz


5

Octave , 9 byte

@()nargin

Hãy thử trực tuyến!

Hàm ẩn danh nhận bất kỳ số lượng đối số nào (và âm thầm loại bỏ lô) và xuất ra số lượng đối số thông qua tích hợp nargin. Điều này không hoạt động trong MATLAB, nơi bạn sẽ cần varargincho phép nhiều đối số tùy ý.



4

Perl 5 , 9 byte

sub{~~@_}

Hãy thử trực tuyến!


Một tìm kiếm nhanh trong các câu trả lời dường như chỉ ra rằng bạn có thể bỏ quasub
ASCII chỉ

2
Protip: TIO cho phép bạn sao chép ở định dạng bài đăng PPCG (ESC, S, G)
ASCII - chỉ

@ ASCII-chỉ Oh tốt đẹp, cảm ơn! :) Về việc bỏ đi sub, tôi không nghĩ vậy. Nó không phải là một chức năng mà không có nó.
Chris

Chỉ có ASCII Tôi mới xem xét câu trả lời mà không có subgiá trị vì kết quả không phải là thứ bạn có thể gọi hoặc gán cho một biến
TonMedel


4

C # .NET, 11 byte

a=>a.Length

Hãy thử trực tuyến.

Giải trình:

Trong C # .NET objectđược sử dụng cho các đối số nhiều loại, cho phép một người vượt qua các số nguyên, chuỗi, ký tự, v.v. như các đầu vào có thể. Ví dụ:

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

C # .NET cũng có thể có kích thước cố định của các đối số tùy chọn. Ví dụ:

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

Và cũng có các biến thể, đó là số lượng đối số tùy chọn không xác định (đó là những gì tôi đã sử dụng trong câu trả lời này). Ví dụ:

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

Thông thường lambdas được tạo ra như thế này:

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)

Nhưng thật không may System.Func, không hỗ trợ paramsvarargs, vì vậy tôi sẽ phải tạo một delegatethay thế:

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

Đó là câu trả lời của tôi cho thử thách này và có thể được tìm thấy trong mã kiểm tra TIO được liên kết.


Hạn chế duy nhất là việc nhập một lượt object[]thích thực tế f(new object[]{1,2,3})sẽ dẫn đến 3 thay vì 1. f(new int[]{1,2,3})vẫn sẽ dẫn đến 1, vì nó diễn giải thành int[]một object. Để có object[]tham số được diễn giải thành một đối tượng duy nhất, nó có thể được truyền tới một đối tượng như thế này : f((object)new object[]{1,2,3}).


Tôi phải nói rằng, nếu đã từng có một câu trả lời khiến tôi ủng hộ bao gồm cả câu hỏi liên quan đến lambda trong câu trả lời C # thì đây sẽ là câu trả lời ... nhưng đây chắc chắn là một giải pháp hợp lệ.
Kamil Drakari

@KamilDrakari Có lẽ thực sự không rõ ràng những gì tôi đã làm mà không mở liên kết TIO, vì vậy tôi đã thêm một lời giải thích.
Kevin Cruijssen

1
@Taemyr Tôi đã thử tìm một giải pháp, nhưng thật không may là không có C # .NET, ngoại trừ việc truyền bất kỳ object[]tham số nào object, như thế này : f((object)new object[]{1,2,3});. Không có cách nào để phân biệt giữa f(new object[]{1,2,3});f(1,2,3);xa như tôi có thể tìm thấy.
Kevin Cruijssen

1
điều này xử lý các tham số mảng một cách chính xác cho một hình phạt rất lớn của byte. Có thể có một cấu trúc ngắn gọn hơn có thể xử lý nó, nhưng nó hoạt động trong thử nghiệm của tôi.
Kamil Drakari

1
@KamilDrakari Hmm, nhưng nó lại thất bại f(1, new object[]{1,2,3})một lần nữa. Không chắc chắn nếu một giải pháp cho hành vi này có thể được tìm thấy.
Kevin Cruijssen

4

Dodos , 32 31 byte

f
	dot i f dab
i
	
	dip dot dab

Hãy thử trực tuyến!

Sử dụng chức năng tăng của Dennis.

Giải trình

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

Ngoài ra, 32 byte không có đệ quy trong hàm mục tiêu (cảm ơn @Leo )

	dot i
i
	dip dot dab dot
	i dab

Hãy thử trực tuyến!

Giải trình

        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)

Đây là một giải pháp có cùng độ dài khác Hãy thử trực tuyến! Tôi dường như không thể hiểu tại sao bạn làm việc mặc dù, bạn có thể thêm một lời giải thích?
Leo

Hey, bạn đã thêm một lời giải thích cho giải pháp của tôi! Tôi muốn một cái cho bạn, tôi biết cách tôi làm việc xD
Leo

1
@Leo xin lỗi vì trả lời trễ, vì tôi đang làm gì, chỉ cần sao chép chức năng của Dennis, sẽ cố gắng hiểu asap. Tôi không biết làm thế nào dodos hoạt động vì vậy tôi đã tìm ra những gì bạn đã làm đầu tiên
ASCII - chỉ

Đừng lo lắng, đó chỉ là một tình huống buồn cười :)
Leo

@Leo ok vậy lời giải thích của tôi có ý nghĩa không? (lưu ý: Tôi đang sử dụng điện thoại di động nên thoải mái chỉnh sửa nó để làm cho nó tốt hơn lol)
ASCII chỉ có

3

C ++, 72 byte

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

Lưu byte bằng cách chỉ làm việc với ints.


Bạn có thể sử dụng sizeof....
LF

3

Rust, 57 byte

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

Giải trình:

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

Kiểm tra:

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 byte

<?=$argc-1;

Dùng thử trực tuyến: 1 đầu vào | 3 đầu vào


Tôi không chắc lắm về điều này (và nó có hiệu lực) vì đây là số lượng đối số được truyền để gọi PHP.
Ismael Miguel

@IsmaelMiguel, xem sự đồng thuận này .
Xù xì

1
Câu hỏi đặt ra yêu cầu rõ ràng một chức năngtrở về số lượng, không hiển thị nó: "... viết một chức năng mà phải mất một số biến của tham số và trả về số đối số"
axiac

1
Trích dẫn lại câu hỏi: "Sử dụng ngôn ngữ bạn chọn, hãy viết một hàm lấy số lượng đối số thay đổi và trả về số lượng đối số mà nó được gọi.". Mã của bạn không chứa các hàm.
Ismael Miguel

@IsmaelMiguel, nếu đó thực sự là trường hợp thì nhiều giải pháp khác cũng sẽ bị vô hiệu. Định mức là cho phép các giải pháp là chương trình hoặc chức năng.
Shaggy

2

Hàng loạt, 50 49 byte

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

Không có nội dung trong Batch, vì vậy chúng tôi phải đi học cũ. Đã lưu 1 byte nhờ @IsmaelMiguel. Đầu ra thông qua mã thoát hoặc lưu 3 byte nếu đầu ra qua biến toàn cục là hợp lệ. Ví dụ về việc sử dụng trong một chương trình đầy đủ:

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

Tôi tin rằng câu trả lời này là câu trả lời đi (phần nào) trái với quy tắc. Batch có một cái gì đó gần với chức năng. Bạn có thể làm một cái gì đó tương tự :a|set r=0&for %%a in (%*)do set/ar+=1( |= dòng mới theo phong cách windows). Giải pháp này là 38 byte. Để thực hiện nó, hãy thực hiện call :a <args>với a goto :eoftrước hàm, là giá trị có sẵn bên trong biến r. Nếu bạn muốn giữ giải pháp của mình, hãy xóa /acái đầu tiên setvà loại bỏ những cái đó @.
Ismael Miguel

@IsmaelMiguel Thích cái này? (Lưu ý: Tôi không bao gồm tên hàm trong số byte, nhưng tôi đã bao gồm trả về hàm, điều này có vẻ hợp lý, vì cần phải có một nơi nào đó.)
Neil

Vâng, chính xác là như vậy. Bắt tốt đẹp với mã thoát! Tôi đã rất ngạc nhiên khi thấy các mã thoát có thể lớn hơn 255. Một ví dụ là danh sách được cung cấp bởi Symantec: symantec.com/connect/articles/ Kẻ
Ismael Miguel

2

Chức năng mã máy x86 32 bit (i386), 13 byte

Quy ước gọi: i386 System V (stack args), với con trỏ NULL là sentinel / terminator cho danh sách end-of-arg-list . (Clobbers EDI, nếu không thì tuân thủ SysV).

C (và asm) không chuyển thông tin loại cho các hàm matrixdic, do đó, mô tả của OP về việc truyền các số nguyên hoặc mảng không có thông tin loại rõ ràng chỉ có thể được thực hiện trong một quy ước truyền một số loại đối tượng struct / class (hoặc con trỏ tới ), không phải số nguyên trần trên ngăn xếp. Vì vậy, tôi quyết định giả định rằng tất cả các đối số đều là con trỏ không phải NULL và người gọi vượt qua một đầu cuối NULL.

Một danh sách con trỏ kết thúc bằng NULL thực sự được sử dụng trong C cho các hàm như POSIXexecl(3) : int execl(const char *path, const char *arg, ... /* (char *) NULL */);

C không cho phép các int foo(...);nguyên mẫu không có đối số cố định, nhưng int foo();có nghĩa tương tự: args không xác định. (Không giống như trong C ++ có nghĩa là gì int foo(void)). Trong mọi trường hợp, đây là một câu trả lời asm. Việc dỗ một trình biên dịch C để gọi hàm này trực tiếp là thú vị nhưng không bắt buộc.

nasm -felf32 -l/dev/stdout arg-count.asm với một số dòng bình luận loại bỏ.

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

Câu hỏi cho thấy hàm phải có thể trả về 0 và tôi quyết định làm theo yêu cầu đó bằng cách không bao gồm con trỏ NULL kết thúc trong số đếm arg. Điều này không tốn 1 byte, mặc dù. (Đối với phiên bản 12 byte, hãy loại bỏ LEA và bỏ ghi chú scasdbên ngoài vòng lặp và xchg, nhưng không phảidec edx . Tôi đã sử dụng LEA vì chi phí giống như ba hướng dẫn khác được đặt cùng nhau, nhưng hiệu quả hơn, do đó chức năng sẽ ít hơn ôi.)

Người gọi C để thử nghiệm :

Được xây dựng với:

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được yêu cầu ngay cả ở -O0 để nói với gcc giả sử rằng các hàm edibị khóa mà không lưu / khôi phục nó, bởi vì tôi đã sử dụng rất nhiều cuộc gọi trong một câu lệnh C ( printfcuộc gọi) thậm chí -O0đang sử dụng EDI. Dường như an toàn cho gcc mainđể chặn EDI từ người gọi của chính nó (bằng mã CRT), trên Linux với glibc, nhưng nếu không thì nó hoàn toàn không có thật để trộn / kết hợp mã được biên dịch với khác nhau -fcall-used-reg. Không có __attribute__phiên bản nào của nó để cho phép chúng ta khai báo các hàm asm với các quy ước gọi tùy chỉnh khác với thông thường.

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

Hai phiên bản khác cũng có 13 byte: phiên bản này dựa trên loopnetrả về giá trị quá cao bằng 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

Phiên bản này sử dụng rep scasd thay vì vòng lặp, nhưng lấy số đếm modulo 256. (Hoặc giới hạn ở mức 256 nếu các byte trên ecxlà 0 khi nhập!)

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

Thật thú vị, nhưng một phiên bản khác dựa trên inc eax/ pop edx/ test edx,edx/ jnzxuất hiện ở mức 13 byte. Đó là một quy ước callee-pop, không bao giờ được sử dụng bởi các triển khai C cho các hàm biến đổi. (Tôi đã đưa addr retr vào ecx và jmp ecx thay vì ret. (Hoặc đẩy / ret để không phá vỡ ngăn xếp dự báo địa chỉ trả về).




Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.