为什么 amsmath 和 \char 以这种方式相互作用?

为什么 amsmath 和 \char 以这种方式相互作用?

我在尝试重新定义 \char 来表示字段的特征时发现了这一点,并收到了一条奇怪的错误消息。下面是一个最小示例,用于演示发生的奇怪事情。

\documentclass[12pt]{article}

\usepackage{amsmath}

\renewcommand{\char}{\stepcounter{section}}

\begin{document}

\section{test}

test$1 + 1 = 2$test$2 + 2 = 4$test

\section{test}

test$1 + 1 = 2$test$2 + 2 = 4$test

\section{test}

\end{document}

如果您排版此内容,您将获得编号为 1、3 和 4 的部分。通过对此进行实验,我确定文档的第一个内联数学、显示数学或对齐环境会导致 \char 被调用一次,从那时起,似乎没有其他任何东西能够再次调用它。这仅在加载 amsmath 包时才会发生。到底发生了什么?有没有什么方法可以让我重新定义 \char 而不会引起奇怪的问题?

答案1

总结

是否可以安全地重新定义\char?没有很多那些最终会被证明是无用的工作。

永远不要\renewcommand对你不了解的命令执行操作。对于你的命令,请执行

\DeclareMathOperator{\Char}{char}

并使用\Char。或者\fldchar,选择你认为最好的名字,但不是 \char

扩展答案

具体的错误是由于在其宏中amsmath使用了,该宏在字体大小改变后每次第一次出现数学公式时都会执行。\char\resetMathstrut@

\def\resetMathstrut@{%
  \begingroup
  \setbox\z@\hbox{%
    \mathchardef\@tempa\mathcode`\(\relax
    \def\@tempb##1"##2##3{\the\textfont"##3\char"}%
    \expandafter\@tempb\meaning\@tempa \relax
  }%
 \edef\@tempa{%
     \ht\Mathstrutbox@\the\ht\z@\relax
     \dp\Mathstrutbox@\the\dp\z@\relax}%
  \expandafter\endgroup\@tempa
}

除了告诉它设置了一个用于对齐环境的数学支柱之外,实际上没有必要描述这个宏的作用。

使用您的代码,此宏仅执行一次,但如果您在参数中添加公式,\section您会看到它会再次执行一次。

有没有办法安全地重新定义\char?是的,有:制作整个 LaTeX 树的副本,\let\primitivechar\char在 (副本) 的开头添加 ;然后用 替换整个树中latex.ltx出现的所有其他。然后重新编译格式。你永远不知道哪个包可能会使用。\char\primitivechar\char

一连串的ack(或grep) 表示\char在总共 960 个文件中出现了 8682 次:

> ack -ch '\\char[^a-z]' /usr/local/texlive/2022/texmf-dist/tex/latex/
8682
> ack -cl '\\char' /usr/local/texlive/2022/texmf-dist/tex/latex/ | wc -l
960

不过,请考虑一下,除了你之外,没有人能够在你的文档上运行 LaTeX。所以你的问题的答案是

是的,但从实际目的来看,不是。

一些背景知识。LaTeX3 的最初目标之一是取消定义每个原语,用别名替换它们。然而,团队意识到这是不切实际的,因为这意味着基本上没有当前的包可以与新版本一起使用,而新版本有成千上万个!

为什么原来的 LaTeX 没有做这个步骤?原因有很多种,主要有以下几点:

  1. 在编写 LaTeX 时,纯 TeX 是唯一可用的格式,并且 LaTeX 借用了几种纯 TeX 构造;

  2. 从纯文本到 LaTeX 的转换会更容易,允许重用代码;

  3. 计算机内存稀缺;真的稀缺。

当 LaTeX2e 发布时,这可能是一个继续进行为每个原语添加别名并用别名替换它们的项目的机会,因为包并不多。但 LaTeX 基本上无法在任何机器上运行,因为每个别名都占用内存空间。如今,这种内存考虑不再是问题,但包却多达数千个。

在某些情况下,可以重新定义一个原语,但只是为了稍微改变它的行为:\input例如,LaTeX 使用 来做到这一点,但重新定义\input最终总会调用原语的别名。

答案2

\char是通过数字访问字符的 TeX 原语,因此重新定义它会破坏所有类型的 latex 构造,而不仅仅是amsmath

\documentclass{article}

\renewcommand{\char}{\stepcounter{section}}


\begin{document}

\begin{picture}(0,0)
\put(0,0){\circle{5}}
\end{picture}
\end{document}

LaTeX 无法选择正确大小的圆。

总是使用\newcommand以避免意外的重新定义。仅\renewcommand当您希望更改现有命令的所有用法的行为时才使用。

相关内容