You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Clang-Format保留宏的反斜杠换行续行符?

如何让Clang-Format保留预处理器宏的反斜杠续行?

我有一段用反斜杠作为续行符的多行预处理器宏代码,执行Clang-Format后,原本的多行结构被强行合并成单行,完全忽略了手动添加的续行反斜杠,生成的单行甚至远超我设置的100列限制。

格式化前的代码

#include "uart0.h"

#if \
    defined(__AVR_ATmega8__)   || \
    defined(__AVR_ATmega8A__)  || \
    defined(__AVR_ATmega16__)  || \
    defined(__AVR_ATmega16A__) || \
    defined(__AVR_ATmega32__)  || \
    defined(__AVR_ATmega32A__)

    #define UART_RX_INTERRUPT USART_RXC_vect
    #define UART_TX_INTERRUPT USART_UDRE_vect
    ...

格式化后的代码

#include "uart0.h"

#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8A__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega16A__) || defined(__AVR_ATmega32__) || defined(__AVR_ATmega32A__)

    #define UART_RX_INTERRUPT USART_RXC_vect
    #define UART_TX_INTERRUPT USART_UDRE_vect
    #define UART_STATUS       UCSRA
    #define UART_CONTROL      UCSRB

我已经设置了AlignEscapedNewlines: Left和ColumnLimit: 100,但问题依然存在,以下是我的完整Clang-Format配置:

Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: Left
AlignConsecutiveAssignments:
    Enabled: True
    AcrossEmptyLines: False
    AcrossComments: False
    AlignCompound: True
    PadOperators: True
AlignConsecutiveBitFields:
    Enabled: True
    AcrossEmptyLines: False
    AcrossComments: False
    AlignCompound: False
    PadOperators: False
AlignConsecutiveDeclarations:
    Enabled: True
    AcrossEmptyLines: False
    AcrossComments: False
    AlignCompound: False
    PadOperators: False
AlignConsecutiveMacros:
    Enabled: True
    AcrossEmptyLines: False
    AcrossComments: False
    AlignCompound: False
    PadOperators: False
#AlignConsecutiveShortCaseStatements: # Version 17
#    Enabled: True
#    AcrossEmptyLines: False
#    AcrossComments: False
#    AlignCaseColons: False
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments:
    Kind: Always
    OverEmptyLines: 0
AllowAllArgumentsOnNextLine: True
AllowAllParametersOfDeclarationOnNextLine: True
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: False
AllowShortEnumsOnASingleLine: False
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: True
AlwaysBreakAfterReturnType: All
AlwaysBreakBeforeMultilineStrings: True
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: False
BinPackParameters: False
BitFieldColonSpacing: After
BraceWrapping:
    AfterCaseLabel: True
    AfterClass: True
    AfterControlStatement: Always
    AfterEnum: True
    AfterExternBlock: True
    AfterFunction: True
    AfterNamespace: True
    AfterStruct: True
    AfterUnion: True
    BeforeCatch: True
    BeforeElse: True
    BeforeLambdaBody: True
    BeforeWhile: True
    IndentBraces: False
    SplitEmptyFunction: True
    SplitEmptyRecord: True
    SplitEmptyNamespace: True
#BracedInitializerIndentWidth: 4 # Version 17
BreakAfterAttributes: Never
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Allman
BreakBeforeConceptDeclarations: Always
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: True
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterColon
BreakStringLiterals: True
ColumnLimit: 100
CompactNamespaces: False
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 0
Cpp11BracedListStyle: False
DerivePointerAlignment: False
DisableFormat: False
EmptyLineAfterAccessModifier: Always
EmptyLineBeforeAccessModifier: Always
FixNamespaceComments: False
IncludeBlocks: Preserve
IncludeCategories:
    - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
      Priority: 2
      SortPriority: 0
      CaseSensitive: False
    - Regex: '^(<|"(gtest|gmock|isl|json)/)'
      Priority: 3
      SortPriority: 0
      CaseSensitive: False
    - Regex: '.*'
      Priority: 1
      SortPriority: 0
      CaseSensitive: False
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: True
IndentCaseBlocks: False
IndentCaseLabels: True
IndentExternBlock: AfterExternBlock
IndentGotoLabels: True
IndentPPDirectives: BeforeHash
IndentRequiresClause: False
IndentWidth: 4
IndentWrappedFunctionNames: False
InsertBraces: True # Possible incorrect code formatting
InsertNewlineAtEOF: True
InsertTrailingCommas: None
IntegerLiteralSeparator:
    Binary: 0
    BinaryMinDigits: 0
    Decimal: 0
    DecimalMinDigits: 0
    Hex: 0
    HexMinDigits: 0
#KeepEmptyLinesAtEOF: False # Version 17
KeepEmptyLinesAtTheStartOfBlocks: False
LambdaBodyIndentation: Signature
LineEnding: LF
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
PPIndentWidth: -1
PackConstructorInitializers: Never
PenaltyBreakAssignment: 0
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyBreakComment: 0
PenaltyBreakFirstLessLess: 0
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 0
PenaltyBreakTemplateDeclaration: 0
PenaltyExcessCharacter: 0
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 0
PointerAlignment: Left
QualifierAlignment: Leave
ReferenceAlignment: Right
#RemoveParentheses: Leave # Version 17
RemoveSemicolon: True
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Always
ShortNamespaceLines: 0
SortIncludes: Never
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: True
SpaceAfterLogicalNot: False
SpaceAfterTemplateKeyword: True
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: True
SpaceBeforeCaseColon: False
SpaceBeforeCpp11BracedList: True
SpaceBeforeCtorInitializerColon: True
SpaceBeforeInheritanceColon: True
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
    AfterControlStatements: True
    AfterForeachMacros: True
    AfterFunctionDefinitionName: False
    AfterFunctionDeclarationName: False
    AfterIfMacros: True
    AfterOverloadedOperator: False
    AfterRequiresInClause: False
    AfterRequiresInExpression: False
    BeforeNonEmptyParentheses: False
SpaceBeforeRangeBasedForLoopColon: True
SpaceBeforeSquareBrackets: False
SpaceInEmptyBlock: False
SpaceInEmptyParentheses: False # Deprecated
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInCStyleCastParentheses: False # Deprecated
SpacesInConditionalStatement: False # Deprecated
SpacesInContainerLiterals: False
SpacesInLineCommentPrefix:
    Minimum: 1
    Maximum: -1
#SpacesInParens: Custom # Version 17
#SpacesInParensOptions: # Version 17
#    InConditionalStatements: False
#    InCStyleCasts: False
#    InEmptyParentheses: False
#    Other: False
SpacesInSquareBrackets: False
Standard: Latest
StatementAttributeLikeMacros:
    - Q_EMIT
StatementMacros:
    - Q_UNUSED
    - QT_REQUIRE_VERSION
TabWidth: 4
UseTab: Never
WhitespaceSensitiveMacros:
    - BOOST_PP_STRINGIZE
    - PP_STRINGIZE
    - STRINGIZE

解决方案

要让Clang-Format尊重预处理器宏的反斜杠续行,需要调整以下几项配置:

  1. 修改BreakBeforeBinaryOperators为NonAssignment
    当前配置的All会让Clang-Format重新排列所有二元运算符,包括预处理器中的||,从而破坏手动续行。改为NonAssignment后,逻辑运算符的换行会被保留。

  2. 启用MacroBlockBegin和MacroBlockEnd
    在配置中添加:

    MacroBlockBegin: '#if'
    MacroBlockEnd: '#endif'
    

    这会让Clang-Format将#if到#endif的代码视为独立块,保留内部的换行结构。

  3. 调整IndentPPDirectives为None
    当前的BeforeHash会修改预处理器指令的缩进,改为None可以确保续行的对齐符合手动编写的格式。

  4. 保留AlignEscapedNewlines: Left
    该配置已正确设置,它会让续行的反斜杠保持左对齐,和原始格式一致。

修改后的关键配置片段:

BreakBeforeBinaryOperators: NonAssignment
MacroBlockBegin: '#if'
MacroBlockEnd: '#endif'
IndentPPDirectives: None

如果还有特定宏需要完全保留格式,可以将其添加到WhitespaceSensitiveMacros列表中,但对于#if这类预处理器块,上述配置已经足够解决问题。

内容的提问来源于stack exchange,提问作者zambetti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 08:47:32