Expansion of \char in \def

This can be done via the \lowercase trick:

\documentclass{minimal}
\usepackage{etoolbox}
\usepackage{xstring}
\makeatletter

\begingroup
  \catcode0=12 %
  \gdef\chrdef#1#2{%
    \begingroup
      \lccode0=\numexpr(#2)\relax
    \lowercase{\endgroup
      \def#1{^^@}%
    }%
  }%
\endgroup

\def\title@A{a A}
\def\title@B{b B}

\def\gettitle#1{
  \IfInteger{#1}{%
    \chrdef\@tmp{#1}%
    \ifcsundef{title@\@tmp}{\@tmp}{\csname title@\@tmp\endcsname}%
  }{%
    \ifcsundef{title@#1}{#1}{\csname title@#1\endcsname}%
  }
}
\begin{document}
\gettitle{65}  \gettitle{A}

\gettitle{66}  \gettitle{B}

\gettitle{67}  \gettitle{C}
\end{document}

Result

\lowercase (a not expandable command) converts the argument character token to its lower case character. This is configured by \lccode. The only exception is zero. If the \lccode is zero for a character, then the character remains unchanged. Therefore the example uses the character with code zero, which can be expressed as ^^@ in TeX notation. However, this character has usually the category code of invalid, there it is changed to 12 (other) in the outside group. Since the changes to \lccode should be reverted afterwards, the macro also uses a group.


The \char primitive isn't expandable. In XeTeX and LuaTeX we have \Uchar, which is and so can generate any character. For pdfTeX, with only 256 possible outcomes, we can set up a look-up table. Something like

\catcode`\@=11 %
\ifdefined\Uchar
  \def\Xchar#1{%
    \detokenize\expandafter{\Uchar\numexpr #1\relax}%
  }
\else
  \catcode`\^^@=12 %
  \begingroup
    \gdef\Xchar#1{%
     \romannumeral-`\0\expandafter\Xchar@aux\expandafter{\numexpr #1\relax}%
    }
    \gdef\Xchar@aux#1{%
      \ifcsname Xchar@\romannumeral #1\endcsname
        \csname Xchar@\romannumeral #1\endcsname
      \else
        \errmessage{Character out of range}%
      \fi
    }
    \count@=-1 %
    \lccode`\X=`\X %
    \loop
      \advance\count@ by 1 %
      \ifnum\count@<256 %
      \lccode`\^^@ = \count@ %
      \lowercase{%
        \expandafter\gdef\csname Xchar@\romannumeral\count@\endcsname{^^@}%
      }
    \repeat
  \endgroup
\fi
\catcode`\@=12 %

provide \Xchar to do the job. A more sophisticated version of the same idea can be used to provide different category code characters, and is implemented as \char_generate:nn in expl3. (The above is expandable at point-of-use as the lookup table is generated in advance.)