Lookup and reference functions

ADDRESS

Matches all 1,304 recorded answers

Recorded: 1,284 in the answer bank and 20 workbook cells. How we measure this · See the Rust code

Local names in 40 languages
LanguageName in Excel
Arabicالعنوان
BulgarianADDRESS
CzechADRESA
DanishADRESSE
GermanADDRESS
GreekADDRESS
English (Australia)ADDRESS
English (United Kingdom)ADDRESS
English (United States)ADDRESS
SpanishDIRECCIÓN
EstonianAADRESS (AADRESS)
FinnishOSOITE
FrenchADDRESS (ADRESSE)
HebrewADDRESS
CroatianADDRESS (ADRESA)
HungarianADDRESS (Cím)
IndonesianALAMAT
ItalianADDRESS
JapaneseADDRESS
Korean주소
LithuanianADRESAS
LatvianADRESE
NorwegianADRESSE
DutchADDRESS
PolishADDRESS (Adres)
Portuguese (Brazil)ENDEREÇO
Portuguese (Portugal)ADDRESS
RomanianADDRESS
RussianADDRESS (АДРЕС)
SlovakADDRESS (ADRESA)
SlovenianADDRESS (NASLOV)
Serbian (Latin)ADRESA
SwedishADDRESS
Thaiที่อยู่
TurkishADRES
UkrainianADDRESS (АДРЕСА)
VietnameseĐỊA CHỈ
Chinese (Simplified)地址
Chinese (Hong Kong)ADDRESS (位址)
Chinese (Traditional)ADDRESS (位址)

Names from Microsoft's support site.

What it does

ADDRESS(row_num, column_num, [abs_num], [a1], [sheet_text])

ADDRESS is a formatter, not a lookup. Given a row number and a column number it renders the text of a cell address in the style you ask for. It does not read the cell, it does not produce a reference value, and it never touches the grid — the row and column numbers may point far outside any sheet's bounds and ADDRESS will still render an address for them, subject to the admissible ranges below.

The rendered string is assembled from four independent decisions:

  1. whether the row part carries a $ (absolute) or not (relative),
  2. whether the column part carries a $,
  3. whether the address is written in A1 notation ($D$5) or R1C1 notation (R5C4), and
  4. whether a sheet qualifier is prefixed (Sheet2!$D$5).

Decisions 1 and 2 are jointly encoded by abs_num; decision 3 by a1; decision 4 by sheet_text. The result is Text under the value-universe chapter's kinds — the same kind you would get from "$D$5" typed as a literal. Nothing downstream treats it as a reference unless you pass it through INDIRECT.

Arguments

ArgumentMeaning
row_numThe row coordinate. Required.
column_numThe column coordinate. Required.
abs_numWhich parts are absolute. Microsoft documents 1 (or omitted) = absolute row and column, 2 = absolute row, relative column, 3 = relative row, absolute column, 4 = both relative.
a1Reference style. Microsoft documents a logical: TRUE or omitted = A1 style, FALSE = R1C1 style.
sheet_textText naming the worksheet (or external workbook and worksheet) to prefix. Omitted means no qualifier at all — not "the current sheet spelled out".

The argument that is most often misread is abs_num. It is not a boolean and it is not a bitmask you can reason your way into: the mapping from 1–4 to the four $ combinations is an arbitrary enumeration you have to look up, and the "natural" reading (that 1 means relative) is backwards. The second most-misread is sheet_text: it is your text, inserted into the result, so quoting for sheet names containing spaces or punctuation is a question about how Excel renders the qualifier, not something you can assume ADDRESS handles for you.

Try it

Input cells (optional)

Example: {"B2": 3, "B3": 4}. A1 holds the formula. Other cells need values before a formula can read them.

Enter a formula, then calculate.

Runs locally in your browser with OneCalc. Its answer may differ from Excel. Use English function names and commas between arguments.

Quirks

Result and edge cases

Return kind: Text. The general argument-preparation and coercion rules are the shared ones — see the call pipeline and coercion and lifting; ADDRESS is prepared under ValuesOnlyPreAdapter, so it never sees a live reference, only numbers, logicals and text that coerce to numbers.

Specific to this function:

  • Out-of-sheet coordinates. Whether a row number beyond the sheet's row count renders, errors, or wraps is a boundary the Handbook has not established for Excel.
  • Fractional coordinates. Whether row_num is truncated, rounded, or rejected is likewise not established here.

Errors

Microsoft's documentation for ADDRESS describes the admissible values of abs_num but does not enumerate an error table on the page as a whole. The conditions the Handbook expects to be error-producing — non-positive coordinates, an abs_num outside 1–4 — are stated here as expected and are on the unchecked list below rather than asserted. #VALUE! is the conventional code for a coercion or domain failure in this family (value universe).

An error value arriving in any argument propagates by the universal rule in coercion and lifting: coercion never silently discards a worksheet error.

How to implement

Notes for implementers

  • Column-number-to-letters is the only interesting algorithm here, and it is a bijective base-26 encoding (A…Z, AA…), not ordinary base 26 — there is no zero digit. Off-by-one bugs at Z/AA and at ZZ/AAA are the classic failure, and any implementation should be probed exactly there.
  • R1C1 output is a different grammar, not a different formatting of the same string. In R1C1, "relative" is expressed with bracketed offsets relative to the calling cell in ordinary formula text — but ADDRESS is given absolute coordinates and no calling cell. What ADDRESS emits for the relative R1C1 cases is therefore a genuine question, not a detail, and it is first on the probe list below.
  • Locale. The rendered separator between sheet qualifier and address, and the quoting of sheet names, are presentation decisions that may vary by locale and by sheet-name content.

Rust code

Show the CalcFunc source of this function

Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.

ADDRESS · 1 lines · calc-func/src/catalogue/host_facts.rs on GitHub
6 address_entry "ADDRESS" (2, 5) [V "row_num", V "column_num", V "abs_num", V "a1", V "sheet_text"] |s, a, sv| { address_fn(s, a) }
address_fn · 51 lines · calc-func/src/catalogue/host_facts.rs on GitHub
fn address_fn(site: &Site<'_>, a: &[CalcValue]) -> Step<CalcValue> {
    let given = |i: usize| a.get(i).is_some_and(|v| !v.is_missing());
    let row = if a[0].is_missing() {
        0
    } else {
        let n = num(site, a, 0)?;
        if !n.is_finite() {
            return fail(WorksheetErrorCode::Value);
        }
        address::address_integer(n)
    };
    let col = {
        if a[1].is_missing() {
            return fail(WorksheetErrorCode::Value);
        }
        let n = num(site, a, 1)?;
        if !n.is_finite() {
            return fail(WorksheetErrorCode::Value);
        }
        address::address_integer(n)
    };
    let abs = if given(2) {
        let n = num(site, a, 2)?;
        if !n.is_finite() {
            return fail(WorksheetErrorCode::Value);
        }
        address::address_integer(n)
    } else {
        1
    };
    let a1 = if given(3) {
        match a[3].core_ref() {
            CoreRef::Logical(b) => b,
            CoreRef::Text(_) => site.argument(3, coerce::logical(&a[3]))?,
            _ => num(site, a, 3)? != 0.0,
        }
    } else {
        true
    };
    let sheet_text = if given(4) {
        Some(text_arg(site, a, 4)?)
    } else {
        None
    };
    if !(1..=4).contains(&abs) {
        return fail(WorksheetErrorCode::Value);
    }
    address::format_address_body(row, col, abs as usize, a1, sheet_text.as_ref())
        .map(CalcValue::text)
        .map_err(Exit::Error)
}
address_integer · 18 lines · calc-func/src/ported/address.rs on GitHub
pub(crate) fn address_integer(number: f64) -> i64 {
    // On ADDRESS's admitted integer range, Excel's observed conversion is
    // floor(RN53(RN64(number + 2^31)) - 2^31). The two rounding steps admit
    // the lower neighbor of each integer through these inclusive thresholds.
    // This reduced comparison avoids platform-dependent extended precision.
    // W111 retains exact-bit boundary probes for both thresholds and all axes.
    let upper = number.ceil();
    let threshold = if upper > 0.0 {
        2.0_f64.powi(-22) + 2.0_f64.powi(-33)
    } else {
        2.0_f64.powi(-23) + 2.0_f64.powi(-34)
    };
    if upper - number <= threshold {
        upper as i64
    } else {
        number.floor() as i64
    }
}
AddressBuffer::literal · 4 lines · calc-func/src/ported/address.rs on GitHub
fn literal(&mut self, text: &str) {
    let remaining = 258usize.saturating_sub(self.0.len());
    self.0.extend(text.encode_utf16().take(remaining));
}
AddressBuffer::integer · 10 lines · calc-func/src/ported/address.rs on GitHub
fn integer(&mut self, number: i64) {
    // Signs are literal fragments; magnitude digits append atomically.
    if number < 0 {
        self.literal("-");
    }
    let digits = number.unsigned_abs().to_string();
    if digits.len() <= 258usize.saturating_sub(self.0.len()) {
        self.literal(&digits);
    }
}
column_label_from_index · 13 lines · calc-func/src/ported/address.rs on GitHub
fn column_label_from_index(mut col: usize) -> Option<String> {
    if col == 0 {
        return None;
    }
    let mut chars = Vec::new();
    while col > 0 {
        let rem = (col - 1) % 26;
        chars.push((b'A' + rem as u8) as char);
        col = (col - 1) / 26;
    }
    chars.reverse();
    Some(chars.into_iter().collect())
}
format_address_body · 62 lines · calc-func/src/ported/address.rs on GitHub
pub(crate) fn format_address_body(
    row: i64,
    col: i64,
    abs_num: usize,
    a1_style: bool,
    sheet_text: Option<&ExcelText>,
) -> Result<ExcelText, WorksheetErrorCode> {
    if !(1..=4).contains(&abs_num) {
        return Err(WorksheetErrorCode::Value);
    }
    let row_relative = !a1_style && matches!(abs_num, 3 | 4);
    let col_relative = !a1_style && matches!(abs_num, 2 | 4);
    let valid_coordinate = |value: i64, limit: i64, relative: bool| {
        if relative {
            (-limit + 1..limit).contains(&value)
        } else {
            (1..=limit).contains(&value)
        }
    };
    if !valid_coordinate(row, 1_048_576, row_relative)
        || !valid_coordinate(col, 16_384, col_relative)
    {
        return Err(WorksheetErrorCode::Value);
    }
    let prefix = match sheet_text {
        Some(sheet) => {
            let mut prefix = quote_sheet_text_if_needed(sheet)?;
            prefix.push(33);
            prefix
        }
        None => Vec::new(),
    };
    // The sheet prefix is constructed before the bounded body append. An
    // admitted escaped name can make the prefix itself 259 UTF-16 units long.
    let mut address = AddressBuffer(prefix);
    if a1_style {
        let col_part = column_label_from_index(col as usize)
            .ok_or(WorksheetErrorCode::Value)?;
        if matches!(abs_num, 1 | 3) {
            address.literal("$");
        }
        address.literal(&col_part);
        if matches!(abs_num, 1 | 2) {
            address.literal("$");
        }
        address.integer(row);
    } else {
        for (label, number, relative) in [("R", row, row_relative), ("C", col, col_relative)] {
            address.literal(label);
            if !relative || number != 0 {
                if relative {
                    address.literal("[");
                }
                address.integer(number);
                if relative {
                    address.literal("]");
                }
            }
        }
    }
    Ok(ExcelText::from_utf16_code_units(address.0))
}

Kernels shared with other functions

Argument and result plumbing

No implementation has been published with a Handbook test suite for this function.

Version differences

The recorded environments below distinguish a reading from a same-input comparison. Counts describe captured inputs in each environment; overlapping captures and comparisons are not totals of unique worksheet calls.

Excel 16.0 buildPlatform and CPUCaptured inputs
20430Windows, 64-bit, CPU not recorded168,940

The record contains no same-input comparison between these environments. Reading different inputs on different builds does not establish either a version change or cross-build agreement.

Recorded environments and comparison details.

Excel 16.0 build 20430

Windows, 64-bit, CPU not recorded

168,940 captured inputs are indexed for this environment. Capture dates: 2026-09-29 to 2026-09-29. This is a reading count, not a comparison with another build.

Alternatives

Relationships

  • INDIRECT is the other half of the classic pair: ADDRESS makes address text, INDIRECT turns address text back into a live reference. That round trip is a common idiom and also a common source of fragility — see the INDIRECT page for why the text hop is not free.
  • CELL("address", ref) answers the inverse question: given a reference, what is its address text. ADDRESS goes from coordinates to text; CELL goes from reference to text.
  • ROW / COLUMN produce the coordinates that ADDRESS consumes.
  • OFFSET and INDEX are what you actually want when your goal is a reference computed from coordinates. Reaching for ADDRESS + INDIRECT to do that job trades a direct reference for a text round trip and, through INDIRECT, for volatility.

Named variants

No named variants are recorded yet.

Suggest a correction or contribute an implementation · For agents