Code 128 subsets, FNC1-FNC4, and the mod-103 check digit
Full reference for Code 128 covering subsets A, B and C, FNC1 through FNC4, the mod-103 check digit with a worked example, and the FNC4 Latin-1 extension. Sourced against ISO/IEC 15417:2007.
Code 128 is a high-density linear barcode that encodes the full 128-character ASCII set, plus the entire ISO/IEC 8859-1 (Latin-1) repertoire by way of an extension symbol. It does this with three character subsets (A, B, and C), four function characters (FNC1 through FNC4), three latch characters, one shift character, and a mandatory mod-103 check digit. The symbology is specified in ISO/IEC 15417:2007 and its Amendment 1:2026. Try it live in the Code 128 generator; the sections below describe what it does under the hood.
This page is a reference. Each section is anchored so external citations can deep-link to a single fact. If you only need one number, jump to control symbol values, FNC values per subset, or the mod-103 calculation.
The three subsets
Code 128 has exactly three character subsets. A symbol stays in one subset until a latch character switches it to another, or a shift character borrows one character from another subset and reverts. FNC4 is the only extension beyond these three.
| Subset | What it encodes | Typical use |
|---|---|---|
| A | ASCII 00-95. Control characters (NUL through US), digits, uppercase letters, and standard punctuation. No lowercase. | Anything that includes ASCII control characters (tab, line feed, group separator) or is uppercase-only. |
| B | ASCII 32-127. Space, digits, uppercase, lowercase, punctuation, and DEL. No control characters below space. | Default subset for general printable text, and the one you will meet most often. |
| C | Pairs of digits 00-99. Each symbol encodes two digits in one position, doubling density. No letters, no punctuation, no control characters. | Long numeric runs. GTIN, SSCC, serial numbers, and most GS1 Application Identifier values. |
Subset C is what makes Code 128 dense for numeric data. A 20-digit serial in Set B costs 20 data symbols; the same serial in Set C costs 10. That density is also the basis of the encoder's subset-selection logic, covered under Set C length optimisation. For a density comparison against other linear codes, see Code 128 vs Code 39.
The encoder picks subsets for you. You do not insert latch or shift characters in your input string; you give the encoder bytes, and it chooses the subset sequence that minimises symbol count. That choice is deterministic and follows the rules under Set C length optimisation.
Start, stop, and the special symbol values
Every symbol value in Code 128 is an integer from 0 to 106. Most values map directly to a character, a different one per subset. Eleven values are reserved for control functions, three start codes, one stop code, three latches, one shift, and the four FNC functions (FNC4 shares its value with a latch). The mod-103 check digit, covered under the mod-103 check digit, also draws from values 0-102.
| Symbol value | Name | Function |
|---|---|---|
103 | START A | Begins a symbol in subset A. |
104 | START B | Begins a symbol in subset B. |
105 | START C | Begins a symbol in subset C. |
106 | STOP | Terminates the symbol. Unique 13-module pattern (every other symbol is 11 modules). |
101 | CODE A | Latch into subset A. In Set A this same value is FNC4. |
100 | CODE B | Latch into subset B. In Set B this same value is FNC4. |
99 | CODE C | Latch into subset C. |
98 | SHIFT | One-character shift between A and B. Not available in or to subset C. |
102 | FNC1 | Application identifier flag (GS1) when first; field separator elsewhere. |
97 | FNC2 | Message append. A and B only. |
96 | FNC3 | Reader programming. A and B only. |
101 in Set A, 100 in Set B | FNC4 | ISO/IEC 8859-1 (Latin-1) extension. Subset A and B only. Not available in C. |
The reuse of values 100 and 101 is the confusing part of reading Code 128 by hand. The same physical bar pattern means three different things depending on the current subset.
- Value 100 is FNC4 in Set B, and a latch to Set B (CODE B) when read from Set A or Set C. Set C has no literal pair at this value, because Set C pairs run 00-99, values 0-99.
- Value 101 is FNC4 in Set A, and a latch to Set A (CODE A) when read from Set B or Set C. Again, it is not a literal pair in Set C.
The decoder tracks the current subset state across the whole symbol; the state is not a property of any one bar pattern. A Code 128 decoder therefore cannot work symbol by symbol in isolation, because every value is interpreted in the context of the previous subset state.
FNC1 through FNC4 values and signalling
Code 128 has exactly four function characters. Each one occupies one symbol position and is encoded as a numeric value, just like a data character.
| Function | Set A | Set B | Set C | Decoded as |
|---|---|---|---|---|
| FNC1 | 102 | 102 | 102 | Application identifier flag, or ASCII GS (0x1D) field separator. |
| FNC2 | 97 | 97 | not available | Message append marker (rarely used in modern systems). |
| FNC3 | 96 | 96 | not available | Reader-programming directive (consumed by reader, not transmitted). |
| FNC4 | 101 | 100 | not available | Latin-1 extension shift or latch. |
FNC1 is the only function character that is valid in all three subsets. FNC2, FNC3, and FNC4 are valid only in subsets A and B. The restriction follows from the design, because subset C is purely a numeric pair encoder and the values 96 and 97 already mean the literal pairs 96 and 97 in C. The standard reserves no slot for FNC2/3/4 inside subset C, so the encoder must latch to A or B before emitting them.
FNC1 as GS1 flag and field separator
FNC1 has two distinct meanings depending on its position in the symbol.
- Immediately after the start character, FNC1 declares the symbol to be a GS1-128 (formerly UCC/EAN-128). The data that follows is structured according to the GS1 Application Identifier system. Decoders that recognise this prefix flag the read as a GS1-formatted symbol; some transmit a leading
]C1AIM identifier prefix to indicate the GS1 mode. - Anywhere else in the symbol, FNC1 is a field separator between two adjacent variable-length AI fields. Decoders typically transmit it as ASCII
GS(Group Separator, 0x1D, decimal 29) so application software can split the data stream cleanly.
The The GS1 Application Identifier table lists which Application Identifiers are fixed-length (no separator needed) and which are variable-length (FNC1 separator required when followed by another AI). For the practical difference between plain Code 128 and a GS1-128 carrying AIs, see GS1-128 vs Code 128.
FNC2 for message append
FNC2 instructs a reader to buffer the current symbol's data and concatenate it with the data of the next symbol read, so two physically separate Code 128 symbols reach the host as a single logical message. FNC2 can appear anywhere in the symbol. It is rare, because concatenation is usually handled at the application layer.
FNC3 for reader programming
FNC3 marks the symbol as a reader-configuration command. The decoder consumes the symbol locally (changes a setting, switches a mode, sets a prefix or suffix) and transmits no payload to the host. The configuration sheets that scanner manufacturers distribute use FNC3 extensively. FNC3 can appear anywhere in the symbol.
FNC4 for the Latin-1 extension
FNC4 is the mechanism by which Code 128 carries characters above ASCII 127, specifically the ISO/IEC 8859-1 (Latin-1) repertoire (values 128-255). Every claim in this section traces back to ISO/IEC 15417:2007 (clause 4.3.4 and Annex A) and the FNC4 clause of the GS1 General Specifications.
FNC4 has two operating modes, a single-character shift and a two-symbol latch. Both modes apply only inside subset A or subset B; FNC4 is not legal inside subset C and must not appear in a Set C run.
Single-shift mode (one FNC4)
A single FNC4, followed by exactly one data symbol, decodes the next symbol's value as a Latin-1 character at value + 128. After that one character, the decoder reverts to plain ASCII for the next symbol. The shift consumes one symbol position (the FNC4 itself) and applies to exactly one following data symbol.
To encode the Latin-1 character é (e-acute, Latin-1 value 233, hex E9) inside a Set B run, the encoder emits FNC4 and then the symbol for i.
Stream: [data...] FNC4(100) i(value 73) [data...]
Decoded: [data...] é (decoded char 105 + 128 = 233) [data...]
Set B symbol value 73 is the lowercase letter i (ASCII 105). With FNC4 in effect, the decoder adds 128 to the decoded character value, yielding 233, which is é in Latin-1. The FNC4 only modifies the single immediately-following symbol; the next symbol after that decodes normally.
Latch mode (two consecutive FNC4)
Two consecutive FNC4 symbols latch the decoder into Latin-1 mode. Every following data symbol in the current subset has +128 applied to its decoded value until the latch is cleared. Any of the following clears it.
- A single FNC4 appears, which acts as a one-character revert to plain ASCII (the next symbol decodes as plain Set A or B; the symbol after that resumes Latin-1).
- Two consecutive FNC4 symbols appear, which un-latch back to plain ASCII for all following symbols.
- The symbol ends.
Code set and shift characters keep their normal effect inside a latched run, so switching between Set A and Set B does not clear Latin-1 mode.
The latch is the only practical way to encode a long run of Latin-1 text. Without it, every Latin-1 character would cost two symbols (one FNC4 plus the data symbol), doubling the symbol count for non-ASCII text.
The GS1 General Specifications §5.4.3 forbid FNC4 inside GS1-128 symbols, because GS1 Application Identifier data is restricted to invariant printable ASCII. FNC4 is therefore a feature of plain Code 128 only.
Complete value-to-character mapping
The canonical Code 128 character set has 107 symbol values (0-106), each interpreted differently depending on the active subset. Set A and Set B agree on values 0-63 (the printable ASCII range from space through underscore). They diverge from value 64 onward, where Set A continues into ASCII control characters and Set B continues into lowercase plus DEL. Set C is purely numeric pairs.
| Value | Set A | Set B | Set C |
|---|---|---|---|
| 0 | SP | SP | 00 |
| 1-15 | ! " # $ % & ' ( ) * + , - . / | same as A | 01-15 |
| 16-25 | 0-9 | 0-9 | 16-25 |
| 26-31 | : ; < = > ? | same as A | 26-31 |
| 32 | @ | @ | 32 |
| 33-58 | A-Z | A-Z | 33-58 |
| 59-63 | [ \ ] ^ _ | same as A | 59-63 |
| 64 | NUL (ASCII 0) | ` (backtick) | 64 |
| 65-90 | SOH-SUB (ASCII 1-26) | a-z | 65-90 |
| 91-95 | ESC FS GS RS US (ASCII 27-31) | { | } ~ DEL | 91-95 |
| 96 | FNC3 | FNC3 | 96 |
| 97 | FNC2 | FNC2 | 97 |
| 98 | Shift B | Shift A | 98 |
| 99 | CODE C | CODE C | 99 |
| 100 | CODE B | FNC4 | CODE B |
| 101 | FNC4 | CODE A | CODE A |
| 102 | FNC1 | FNC1 | FNC1 |
| 103 | START A (only valid as first symbol) | ||
| 104 | START B (only valid as first symbol) | ||
| 105 | START C (only valid as first symbol) | ||
| 106 | STOP (13-module pattern; only valid as last symbol) | ||
The bar/space pattern for each value (three bars and three spaces, summing to 11 modules) is identical across subsets. The subset only changes the character interpretation, never the printed pattern. The pattern table itself is reproduced in full in the Wikipedia article on Code 128; this article does not duplicate it.
Subset switching with shift and latch
There are two ways to step out of the current subset, and they do different jobs.
SHIFT (value 98) applies to one character only. SHIFT exists only between subsets A and B. In Set A, value 98 means "interpret the next symbol from Set B, then return to Set A". In Set B, value 98 means "interpret the next symbol from Set A, then return to Set B". SHIFT is not legal in Set C and cannot reach Set C.
CODE A, CODE B, and CODE C (values 101, 100, 99) are permanent latches. The decoder switches subset and stays there until another latch occurs. Latches between any two subsets are legal in either direction. The latch consumes one symbol position.
Use SHIFT when exactly one character requires the other subset and the surrounding text is in the current subset. Use a latch when a run of characters belongs in the other subset. Each SHIFT costs one symbol per foreign character, while a latch costs one symbol to enter the other subset and one to come back, so at two consecutive foreign characters the two approaches cost the same and from three onward the latch is cheaper. The encoder calculates this for you.
Take the literal payload ABC123abc. Latching into Set C for the digits would cost a CODE C symbol going in and a CODE B symbol coming out, and Set C can only take 12 as a pair, leaving the 3 to be encoded after latching back, so the latches cost more than they save. Set B handles the uppercase, the digits, and the lowercase without any latch, so the encoder selects START B.
Tokens: START B A B C 1 2 3 a b c [check] STOP
Values: 104 33 34 35 17 18 19 65 66 67 [check] 106
One start, nine data symbols, one check, one stop, twelve symbols in all.
The mod-103 check digit
Every Code 128 symbol carries a mandatory check digit. It is calculated over the start character and all data symbols (including any FNC, SHIFT, and CODE characters), and it sits between the last data symbol and the STOP. The check digit is one symbol value (0-102), encoded with the same bar pattern that the corresponding character would use in the current subset at that position.
Formula
check = (StartValue + sum_over_i(SymbolValue[i] * i)) mod 103
where i = 1, 2, 3, ... over each data symbol in order
The start character's value contributes with weight 1 (no multiplier). The first data symbol contributes with weight 1, the second with weight 2, and so on. FNC, SHIFT, and CODE characters contribute their symbol values with the same positional weight as any data character. The result, taken modulo 103, is the check symbol value.
Worked example with payload PJJ123C
The encoder selects START B (value 104) because the payload mixes uppercase and digits, and the digit run 123 is too short to pay for a CODE C latch. The data symbols and their Set B values are in the table.
| Position i | Symbol | Set B value | i × value |
|---|---|---|---|
| (start) | START B | 104 | 104 |
| 1 | P | 48 | 48 |
| 2 | J | 42 | 84 |
| 3 | J | 42 | 126 |
| 4 | 1 | 17 | 68 |
| 5 | 2 | 18 | 90 |
| 6 | 3 | 19 | 114 |
| 7 | C | 35 | 245 |
The sum is 104 + 48 + 84 + 126 + 68 + 90 + 114 + 245 = 879.
The check digit is 879 mod 103. Since 103 × 8 = 824 and 879 - 824 = 55, the check digit is 55.
The final symbol stream is
START B(104) P(48) J(42) J(42) 1(17) 2(18) 3(19) C(35) [check=55] STOP(106)
Converting the remainder to a symbol pattern
The check digit is a number from 0 to 102. To convert it back to the bar/space pattern that gets printed, look it up in the Code 128 character set table by symbol value. The check digit uses the same value-to-pattern mapping as any other symbol; there is no separate check character set. In the example above, value 55 in Set B is the character W, and the printed bar pattern for the check position is exactly the bar pattern of W.
The check digit's value is interpreted in the subset that is active at its position, which is the same subset the last data symbol was in. If the symbol latched to Set C immediately before the check digit, the check digit is rendered with Set C's pattern for that value. The visual character may be a digit pair, a letter, a control character, or a function character; only the bar pattern matters for verification.
Worked example in Set C with 00102030405060
A 14-digit numeric payload with even length, all digits, fits cleanly in Set C from start to finish. The encoder selects START C (value 105). Each pair of digits is one symbol value, so 00=0, 10=10, 20=20, 30=30, 40=40, 50=50, and 60=60.
| Position i | Pair | Set C value | i × value |
|---|---|---|---|
| (start) | START C | 105 | 105 |
| 1 | 00 | 0 | 0 |
| 2 | 10 | 10 | 20 |
| 3 | 20 | 20 | 60 |
| 4 | 30 | 30 | 120 |
| 5 | 40 | 40 | 200 |
| 6 | 50 | 50 | 300 |
| 7 | 60 | 60 | 420 |
The sum is 105 + 0 + 20 + 60 + 120 + 200 + 300 + 420 = 1225.
The check is 1225 mod 103. 103 × 11 = 1133, and 1225 - 1133 = 92, so the check digit value is 92.
Set C value 92 is the literal pair 92. The check position prints with the bar pattern for value 92, and a decoder transmits no character for it (the check digit is consumed by the decoder, never sent to the host). The final symbol stream is ten symbols (1 start + 7 data + 1 check + 1 stop). The same 14 digits in Set B would take 17 symbols (1 start + 14 data + 1 check + 1 stop), so Set C saves 7 symbols.
Worked example with FNC4 and café au lait
The string café au lait contains one Latin-1 character (é, value 233) embedded in lowercase ASCII. Given Latin-1 input, there are two ways to encode it, and the encoder picks the cheaper one.
The first is a single FNC4 shift. Stay in Set B, emit FNC4 immediately before é, then continue. It costs one extra symbol (the FNC4) for the one Latin-1 character, so the 12 characters of the string become 13 data symbols.
The second is an FNC4 latch followed by an unlatch, two FNC4s to enter Latin-1 mode and two more to leave it. That costs four extra symbols, worse than the shift for a single Latin-1 character, so the encoder uses the shift.
A latch costs four overhead symbols (two FNC4 to enter and two to leave), so mid-string it breaks even at four consecutive Latin-1 characters and is cheaper from five. For a long Latin-1 string the latch is essential; for one stray accent, the single shift wins.
The Code 128 generator on this site reads its input as UTF-8, so é arrives as two bytes (hex C3 and A9), both above 127. Each byte gets its own FNC4 shift, so the generator emits 15 data symbols for this string, 18 symbols in all with the start, check and stop characters. The 13-symbol form above needs Latin-1 bytes as input, which this generator does not produce.
AIM identifier prefixes
Code 128 decoders that support the AIM Symbology Identifier transmission format prepend a three-character prefix to the data stream that identifies the symbology and any in-band variants. For Code 128 the prefix is ]C followed by a single-digit modifier.
| Prefix | Meaning |
|---|---|
]C0 | Standard Code 128 (no FNC1 in first position). |
]C1 | GS1-128 (FNC1 in first position). |
]C2 | FNC1 in second position. |
]C4 | Concatenation per ISBT 128 (blood transfusion) has been performed; the concatenated data follows. |
The prefix is not part of the symbol's data; the decoder generates it from the symbol's structure. A host that needs to know whether a Code 128 symbol carries GS1-formatted data should read this prefix.
Total symbol length
Every Code 128 data character (and every start, latch, shift, FNC, and check) is exactly 11 modules wide, encoded as three bars and three spaces in a fixed widths-pattern. The STOP is 13 modules, three bars and three spaces plus a final two-module bar that closes the symbol.
Total modules = 11 * (data_symbols + start + check) + 13_for_stop
= 11 * (n + 2) + 13
= 11n + 35
where n = number of data symbols (excluding start, check, and stop)
Add quiet zones of at least ten modules on each side. The minimum X-dimension is application-specific; for retail and shipping labels, see how to print barcode labels that scan for X-dimension and quiet-zone targets.
X-dimension and printed width
The X-dimension is the width of the narrowest module, measured in the printed symbol. Code 128 has no fixed X-dimension. ISO/IEC 15417 leaves it to the application, and the GS1 General Specifications symbol specification tables give 0.250 mm as the absolute minimum and 1.016 mm as the maximum for general distribution. GS1-128 retail and logistics labels typically use 0.495 mm (about 19.5 mil) to 0.940 mm (37 mil), with 0.495 mm the floor for SSCC-18 shipping labels per GS1 General Specifications §5.12.3. At smaller X-dimensions the symbol is denser but more sensitive to print quality and scanner resolution; at larger X-dimensions the symbol takes more horizontal space but is more forgiving.
The printed width in millimetres is therefore X × (11n + 35) plus quiet zones. A 12-character Set B payload (n=12) at X = 0.5 mm prints as roughly 12 × 11 + 35 = 167 modules × 0.5 mm = 83.5 mm, plus 5 mm of quiet zone on each side, 93.5 mm in total. That is the budget you have when laying out a label; if it does not fit, either drop the X-dimension or shorten the payload.
Print verification
Code 128 has no error correction. The mod-103 check digit catches single-symbol errors but cannot recover from a misread, so print quality is the dominant factor in scan reliability. The applicable verification standard is ISO/IEC 15416:2025 for linear barcode print quality, which assigns a letter grade A-F based on decode, minimum reflectance, symbol contrast, minimum edge contrast, modulation, defects, and decodability. Most retail and logistics applications require grade C (1.5) or better; pharmaceutical and medical-device labelling under GS1 Healthcare typically requires grade 1.5 with a 10 mil aperture under 670 nm light, written 1.5/10/670.
Set C length optimisation
The encoder switches into Set C when a long enough run of digits makes the density saving outweigh the cost of the CODE C latch. The exact breakeven depends on whether Set C is at the start of the symbol (where it costs only the START C character, no latch) and whether the digit run has even length (Set C requires digit pairs).
The GS1 General Specifications §5.4.7.7 (informative, copied from ISO/IEC 15417 Annex E) give the optimisation rules, summarised here.
- If the entire symbol is digits and the count is even, use START C and stay in C for the whole symbol.
- If the symbol begins with four or more digits, start in C; otherwise start in A or B.
- Inside an A or B run, switch to C when six or more consecutive digits remain (four if at end-of-data, because there is no latch back).
- If the digit run has odd length, the last digit is encoded in A or B with a CODE A or CODE B latch.
These rules are what "the encoder picks subsets for you" means in practice. The rules are informative. Any valid choice of code sets is conformant, and a decoder must accept a symbol that uses a different valid combination.
GS1-128 = Code 128 + FNC1 first
GS1-128 is plain Code 128 with one extra rule, that FNC1 must appear in the first data position. That single FNC1 declares the symbol to be a GS1-128 carrying Application Identifier data. Everything in this article applies to GS1-128 symbols equally, with two adjustments.
- FNC4 (and therefore the Latin-1 extension) is forbidden in GS1-128. AI data is restricted to invariant printable ASCII.
- FNC1 in non-first positions inside a GS1-128 is the field separator between adjacent variable-length AI fields. Decoders transmit it as ASCII GS (0x1D).
For the practical encoding differences and a payload-by-payload comparison, see the GS1-128 generator and GS1-128 vs Code 128.
Common mistakes
- Inserting FNC, SHIFT, or CODE characters into your input by hand. The encoder does this for you. Inserting them yourself produces a symbol whose data stream contains literal bytes that look like control characters, which breaks decoders that interpret them and confuses ones that do not.
- Mixing subsets when you do not need to. If your data is all uppercase plus digits, Set B handles it. Force Set A only when your data has ASCII control characters below space.
- Omitting the check digit. Code 128 has no error correction, so the check digit is the only safety net. A symbol without it will not decode reliably and is non-conformant.
- Trying to use Set C with an odd-length digit run. Set C encodes pairs. The encoder handles odd runs by encoding the last digit in A or B; pad with a leading or trailing zero only when that zero is part of your real data.
- Using FNC4 inside Set C, or inside a GS1-128. FNC4 is not legal in Set C, and it is forbidden in GS1-128 by GS1 §5.4.3. The encoder will reject this combination.
- Hand-calculating the check digit and forgetting that the start character contributes with weight 1. The start character is included in the weighted sum. Skipping it produces a check digit that is off by exactly the start character's value, which is silently wrong.
- Quiet zones too narrow. Code 128 needs at least ten modules of quiet zone on each side. A quiet zone that is too narrow makes a barcode that looks fine fail to scan. For diagnosis, see why won't my barcode scan.
References
- ISO/IEC 15417:2007 Code 128 bar code symbology specification (paywalled; this article cites it as primary).
- ISO/IEC 8859-1 Latin-1 character set (the FNC4 extension target).
- GS1 General Specifications (free; §5.4.3 FNC4 restriction; §5.4.7.7 length optimisation, informative; the AI catalogue is at ref.gs1.org/ai).
- Wikipedia, Code 128 (the encoded-bars table is reproduced there in full; this article does not duplicate it).
Printing thousands of Code 128 labels for cartons, totes, or asset tags? The Code 128 batch generator takes a CSV. If you are still picking the symbology, see Code 39 vs Code 93 vs Code 128.
Checked against ISO/IEC 15417:2007 and GS1 General Specifications Release 26.0 (January 2026).