LearnReferencePortability

Where implementations differ

The original definition of brainfuck is a table and three sentences. It does not say how large a number a cell can hold, what happens at the ends of the tape, or what the read command does when the input has run out. Implementations fill these gaps in different ways, and already did so in 1993: the compiler and the interpreter in the original package do not agree with each other [1].

Why there are differences

Nobody ever wrote a standard. The author says so: there is no formal standard, and people disagree about how large a cell is and about what happens at the end of the input [2]. What exists are three careful descriptions by other people, which mostly agree: Brian Raiter's "Portable Brainfuck" [3], Daniel Cristofani's reference and his letter to implementors [4] [5], and the conventions on the Esolang wiki [6].

The differences are as old as the language. The 1993 package holds a compiler and an interpreter, and reading their sources shows that they differ [1]:

So "what the original did" is not one answer.

Cell size and wrapping

The program below is one command, run on cell 0. Choose the cell size and the command, and slide the number cell 0 starts at: to 255 for +, or to 0 for -. Press Play:

With 8 bits and a start of 255, the one + left 0: the cell went round. Below 0 comes the largest number the cell can hold, and one more than the largest number is 0. This is called wrapping. With cells of 8 bits the largest number is 255, so 255 + 1 = 0 and 0 − 1 = 255; choose 16 bits and the same commands give 256 and 65,535. The values of a cell are a ring.

What the descriptions say:

Why it matters:

A program can find out the size of its cells by counting how often it can double a number before it becomes 0. A well-known test program, bitwidth.b, does this and reports what it found [7].

The length of the tape and its ends

The original gives 30,000 cells [1], and that number became the custom: Cristofani and the Esolang wiki both ask for at least 30,000 [4] [6]. Raiter's minimum is 9,999, so that very small interpreters can keep the pointer in four digits [3]. Many implementations give more, or let the tape grow.

The pointer starts on the leftmost cell. The tape below has six cells (I'm showing six; the original has 30,000). Slide the number of moves to the right, then the number of moves to the left, and press Play:

Five moves to the right bring the pointer to the last cell. A sixth, or one move left of the first cell, takes it off the tape, and this machine stops with a message. Moving left from the leftmost cell is an error in the program. What happens then is "unpredictable" in Cristofani's word [4] and undefined in Raiter's [3]. In practice an implementation does one of these:

Some very short programs use cells to the left of the start on purpose. The shortest known "Hello, World!" needs five of them [6]. Such a program is short, not portable.

The end of the input

The program below copies its input to its output: read, and while the cell is not 0, print and read again. The input is "hello", and you can change it. Choose what the read command does at the end of the input, and press Play:

The loop ends when a read gives 0. That works only where the read command stores 0 at the end of the input. Where it stores −1 the cell becomes 255 and the program prints that for ever. Where the cell is left as it was, the program prints the last letter for ever. The figure follows a run for at most 5,000 steps and says so when the program is still going, because that run would never reach its end.

These are the three behaviours you will meet: store 0, store −1, or leave the cell unchanged [5] [3] [6]. Raiter calls it "frequently the most problematic issue" for a programmer who wants a program to run everywhere [3]. Cristofani prefers "unchanged", because a program can then choose its own value by setting the cell just before it reads; he asks implementations to offer all three [5].

The next program does the same job but is written to stop under all three. Run it under each of them in turn:

Now the status line always says it finished. Before every read the program empties the cell with [-]. After the read the cell is 0 in two of the three cases. Then it adds one: in the third case, −1 becomes 0. It goes on only if the cell was neither. The price: the program also stops at a character with code 0 or 255. Ordinary text has neither.

New lines

Operating systems mark the end of a line in different ways: one character with code 10, or a 13 followed by a 10. Brainfuck programs almost always use 10 alone, as Müller's own example programs do [5] [1]. Cristofani asks implementations to make this work on every system: a program should receive a 10 for each end of line in its input, and a 10 it prints should end a line, with an option to switch that translation off for input that is not text [5].

For a program this means: print 10 for a new line and expect 10 at the end of a line you read. If you run it somewhere that sends 13 as well, treat 13 as a character to skip.

Smaller differences

Brackets that do not match
The original compiler does not check; the original interpreter reports them [1]. Most implementations today refuse to run such a program.
The debug command #
The original interpreter prints the first ten cells when it meets a #, if it was started with an extra argument [1]. Some implementations kept this. Everywhere else # is a comment. Müller's own "Hello World!" has one in it.
The separator !
An interpreter that reads the program and its input from the same stream needs to know where one ends. The custom is an exclamation mark [5]. In a program file it is a comment.
When output appears
A program that asks a question and waits for an answer needs its output shown at once, not saved up until the end. Cristofani asks for this [5]; not every implementation does it.
Characters above 127
The original worked with single bytes. What a byte above 127 looks like on screen depends on the system; today it is usually read as part of a UTF-8 character [6]. A program that prints only codes 10 and 32 to 126 is safe.

Compatibility table

The table below puts the answers side by side. The first two columns are the two programs of the 1993 package, read from their sources. The next three are the written descriptions. The last is the machine in the figures of this reference.

What six implementations and descriptions say about each open point. Read along a row. "Not said" means the source is silent. Sources: the 1993 package [1], Raiter [3], Cristofani [4] [5], the Esolang wiki [6].
Open point1993 compiler1993 interpreterRaiter, "Portable Brainfuck"CristofaniEsolang wikiThe figures here
Cell sizeone byte (the first version: 32 bits)one C charat least 0 to 127at least one byte, usually one bytenormally 8 bits8 bits; 16 or 32 where offered
Past the largest valuewraps (a byte addition)whatever a char doesusually wraps; not requiredmay or may not wrapshould wrapwraps
Cells30,000 (README)5,000 declared; error past cell 100at least 9,999at least 30,000at least 30,000a short tape, as many cells as are drawn
Pointer off the tapenot checked"RANGE ERROR", stopsundefinedunpredictableno cells left of the startstops with a message
Read at end of inputcell unchanged (our reading of the source)stores the value of getchar(), in C normally −1one of: 0, −1, unchangedprefers unchanged; offer all threeoffer all three0; or −1 or unchanged where offered
New linenot said; the examples print 10not saidnot said10, translated for the system1010
Unmatched bracketsnot checked"UNBALANCED BRACKETS"undefinednot saidnot saidrefuses to run
Other charactersignoredignored; # prints cellsignoredignored; # and ! allowedignoredignored

The chat programs of this site are outside this table on purpose: they need 32-bit wrapping cells and a tape of 188 million cells or more. See Notable programs.

Programs that work everywhere

Seven rules. A program that keeps them runs the same on almost every implementation.

  1. Keep every cell between 0 and 127 if you can; never above 255. Then the size of a cell does not matter.
  2. Do not count on wrapping. Never take one off a cell that holds 0, and never empty a cell with [+]. If you do use wrapping, say so in a comment.
  3. Never move left of the cell you started on.
  4. Use fewer than 9,999 cells, or at least fewer than 30,000.
  5. Empty a cell before you read into it, and treat both 0 and "all ones" as the end of the input, as the second program under the end of the input does.
  6. Print 10 for a new line, and print only codes 10 and 32 to 126.
  7. Match your brackets, and keep punctuation out of comments.

To see what an implementation does, run Cristofani's small test programs on it. They report how new lines and the end of the input are handled and how far the tape reaches [10].

And when a program does need something special, as many good ones do, say what it needs at the top: the cell size, the tape length, the behaviour at the end of the input.

Limits

Read next

Notes and sources

Where a source is a community wiki or the author's own account, the entry or the text says so.

  1. Urban Müller, brainfuck-2.lha, Aminet, dev/lang, dated 9 June 1993: the package page on Aminet. We read the files in the archive: README, bfc.asm (the compiler), bfi.c (the interpreter) and the six example programs. Sizes and dates are those of the archive listing. Opened 11 October 2026.
  2. Urban Müller, talk at Tamedia TX, 2017, read as the community transcript on the Esolang wiki: Tamedia TX 2017 transcript. The transcript says its last page is missing. Wikipedia gives the title as "Brainfuck, or how I learned to change the problem" and the date as 13 June 2017; we did not watch the recording. Opened 11 October 2026.
  3. Brian Raiter, "Portable Brainfuck": the portability page on muppetlabs.com. Opened 11 October 2026.
  4. Daniel B Cristofani, "Yet another brainfuck reference": the reference on brainfuck.org. Opened 11 October 2026.
  5. Daniel B Cristofani, "The Epistle to the Implementors": the epistle on brainfuck.org. Opened 11 October 2026.
  6. Esolang wiki, "Brainfuck": the wiki article on brainfuck. A community wiki; we use it for conventions and for its list of results, and name it where it is our only source. Opened 11 October 2026.
  7. rdebath, Brainfuck repository: rdebath/Brainfuck on GitHub. Holds the Tritium interpreter, translators to many languages, test programs and a copy of Müller's 1993 compiler. Opened 11 October 2026.
  8. Esolang wiki, "Brainfuck constants": the wiki's table of constants. Opened 11 October 2026.
  9. shinh, ELVM Compiler Infrastructure, README: shinh/elvm on GitHub. Opened 11 October 2026.
  10. Daniel B Cristofani, tests.b: test programs for implementations on brainfuck.org. Opened 11 October 2026.