禁止C预处理程序更改缩进

时间:2019-07-05 09:24:51

标签: c c-preprocessor

示例(请注意,此代码中恰好有一个TAB,显示为8个空格):

int main()
{
   int x = 1;
   if (x == 1)
   {
      x = 2;
      if(x == 2)
      {
         x = 3; /* indented with TAB */
      }
   }
}

g++ -Eclang++ -E都将其转换为:

int main()
{
   int x = 1;
   if (x == 1)
   {
      x = 2;
      if(x == 2)
      {
  x = 3;
      }
   }
}

另一个例子:

int main()
{
   int x =   ( 1 + 3);
}

->

int main()
{
   int x = ( 1 + 3);
}

它将制表符替换为一个空格(在第一个示例中),并将连续的空格替换为一个(在第二个示例中)。我可以强迫它不这样做吗?

1 个答案:

答案 0 :(得分:3)

这实际上不是对“如何使预处理器保留制表符”问题的答案;我将问题重新解释为“如何通过预处理保留选项卡”。

类似于Unix的发行版应随附Posix expandunexpand实用程序,它们分别将制表符扩展为空格,并用制表符代替空格序列。您可以轻松地使用它来保留前导标签通过预处理器的过程:

$ # '-i' is a Gnu extension. Leave it out if you have a Posix expand.
$ expand -i tabbed.c | gcc -E - | unexpand
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "<stdin>"
int main()
{
   int x = 1;
   if (x == 1)
   {
      x = 2;
      if(x == 2)
      {
         x = 3;
      }
   }
}

(注意:x = 3行的开头有一个选项卡,尽管它没有通过复制粘贴到SO中来实现。)

GCC(和clang)预处理器将非前导空格(包括注释)标准化为单个空格字符,因此您可以做很多工作。因此,在上面的示例中,我对-i使用了Gnu扩展名expand选项,导致该选项仅在前导空格中扩展制表符。 (unexpand仅查看前导空格,除非您提供-a选项。)仅当您将原始制表符放在字符串或字符文字中而不是\t中时,此选项才有用。大概你不这样做。

上面显示的预处理器输出与预处理tabbed.c的结果的直接不同之处在于,行指令引用的是<stdin>,而不是文件名。将#line 1 "tabbed.c" 1放在输入流之前是一个不完善的解决方案,但它至少会通过#line指令。您可以使用sed或其他一些行编辑器来修改生成的行号指令。