Difference between revisions of "Coding Style"

From ReactOS Wiki
Jump to: navigation, search
m
(Three-point fixes in the code examples)
 
(30 intermediate revisions by 11 users not shown)
Line 3: Line 3:
 
As much existing ReactOS code as possible should be converted to this style unless there are reasons against doing this (like if the code is going to be rewritten from scratch in the near future). See [[#Notes on reformatting existing code|Notes on reformatting existing code]] for more details.
 
As much existing ReactOS code as possible should be converted to this style unless there are reasons against doing this (like if the code is going to be rewritten from scratch in the near future). See [[#Notes on reformatting existing code|Notes on reformatting existing code]] for more details.
  
Code synchronized with other sources (like Wine) must not be rewritten.
+
Code synchronized with other sources (like Wine) must not be rewritten. [https://github.com/reactos/reactos/blob/master/media/doc/3rd%20Party%20Files.txt 3rd Party Files.txt] and [https://github.com/reactos/reactos/blob/master/media/doc/WINESYNC.txt WINESYNC.txt] files can be used for tracking synchronized files.
  
 
== File Structure ==
 
== File Structure ==
Line 10: Line 10:
 
<syntaxhighlight lang="c">
 
<syntaxhighlight lang="c">
 
/*
 
/*
  * PROJECT:       ReactOS Kernel
+
  * PROJECT:     ReactOS Kernel
  * LICENSE:       GNU GPLv2 only as published by the Free Software Foundation
+
  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
  * PURPOSE:       Does cool things like ...
+
  * PURPOSE:     Does cool things like Memory Management
  * PROGRAMMERS:   Arno Nymous (abc@mailaddress.com)
+
  * COPYRIGHT:   Copyright 2017 Arno Nymous <abc@mailaddress.com>
  *                 Mike Blablabla (mike@blabla.com)
+
  *             Copyright 2017 Mike Blablabla <mike@blabla.com>
 
  */
 
  */
 
</syntaxhighlight>
 
</syntaxhighlight>
  
We need to keep some consistency and ensure that licenses can be identified uniquely. Keep in mind that some licenses may be ReactOS-specific. Therefore, please use a precise name for the license and give information where to obtain it.
+
Please use SPDX license identifiers available at https://spdx.org/licenses.
 +
This makes our source file parseable by licensing tools!
  
'''Examples:'''
+
You should add yourself to the <tt>COPYRIGHT</tt> section of a file if you did a major contribution to it and could take responsibility for the whole file or a part of it. Not more than 3 people shall be in that list for each file.
* <tt>GNU GPLv2 only as published by the Free Software Foundation</tt>
 
* <tt>GNU GPLv2 or any later version as published by the Free Software Foundation</tt>
 
* <tt>BSD – See COPYING.ARM in the top-level directory</tt>
 
  
You may add yourself to the <tt>PROGRAMMERS</tt> section of a file if you did a major contribution to it and could take responsibility for the whole file or a part of it.
+
<tt>FILE</tt> line of the old header should be removed.
 
</li>
 
</li>
  
<li>Use a header comparable to the following one for functions:
+
<li>[https://doxygen.reactos.org/ Doxygen] documentation generator is used for ReactOS codebase, so use a proper header for functions, see [[Documentation Guidelines#API Documentation|API Documentation]] for details.</li>
<syntaxhighlight lang="c">
 
/**
 
* @name SomeAPI
 
* @implemented
 
*
 
* Do nothing for 500ms.
 
*
 
* @param SomeParameter
 
* Description of the parameter.
 
*
 
* @param YetAnotherParameter
 
* Bleh, bleh :)
 
*
 
* @return
 
* STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
 
* otherwise.
 
*
 
* @remarks Must be called at IRQL == DISPATCH_LEVEL
 
*
 
*/
 
</syntaxhighlight>
 
</li>
 
 
</ol>
 
</ol>
  
== Indentation ==
+
== Indentation and line width ==
 
<ol>
 
<ol>
<li>Indent with 4 spaces, don’t use tabs!</li>
+
<li>Line width must be at most <b>100 characters</b>.</li>
 +
<li>Do not add a space or tab at the end of any line.</li>
 +
<li>Indent with <b>4 spaces</b>, don’t use tabs!</li>
 
<li><p>Indent both a case label and the case statement of a switch statement.</p>
 
<li><p>Indent both a case label and the case statement of a switch statement.</p>
  
Line 65: Line 43:
 
         DoSomething();
 
         DoSomething();
 
         break;
 
         break;
 +
 +
    case 2:
 +
    {
 +
        DoMany();
 +
        ManyMore();
 +
        OtherThings();
 +
        break;
 +
    }
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 70: Line 56:
 
'''Wrong:'''
 
'''Wrong:'''
 
<syntaxhighlight lang="c">
 
<syntaxhighlight lang="c">
switch (Condition)
+
switch(Condition)
 
{
 
{
 
case 1:
 
case 1:
 
     DoSomething();
 
     DoSomething();
 
     break;
 
     break;
 +
case 2:
 +
    DoMany();
 +
    ManyMore();
 +
    OtherThings();
 +
    break;
 
}
 
}
 +
</syntaxhighlight>
 +
</li>
 +
<li><p>When a function call does not fit onto a line, align arguments like this:</p>
 +
 +
<syntaxhighlight lang="c">
 +
FunctionCall(arg1,
 +
            arg2,
 +
            arg3);
 +
</syntaxhighlight>
 +
 +
</li>
 +
<li><p>Function headers should have this format (preserving the order as in the example):</p>
 +
 +
<syntaxhighlight lang="c">
 +
static // scope identifier
 +
CODE_SEG("PAGE") // section placement
 +
// other attributes
 +
BOOLEAN // return type
 +
FASTCALL // calling convention
 +
IsOdd(
 +
    _In_ UINT32 Number);
 
</syntaxhighlight>
 
</syntaxhighlight>
 
</li>
 
</li>
Line 181: Line 193:
 
{
 
{
 
     // This is a comment
 
     // This is a comment
 +
    DoSomething();
 +
}
 +
 +
if (A_Very || (Very && Long || Condition) &&
 +
    On_Many && Lines)
 +
{
 
     DoSomething();
 
     DoSomething();
 
}
 
}
Line 208: Line 226:
 
if (Condition)
 
if (Condition)
 
     // This is a comment
 
     // This is a comment
 +
    DoSomething();
 +
 +
if (A_Very || (Very && Long || Condition) &&
 +
    On_Many && Lines)
 
     DoSomething();
 
     DoSomething();
  
Line 228: Line 250:
 
</li>
 
</li>
  
<li><p>Avoid too many levels of cascaded control structures. Prefer a “linear style” over a “tree style”. Use <code>goto</code> when it helps to make the code cleaner (e.g. for cleanup pathes).</p>
+
<li><p>Avoid too many levels of cascaded control structures. Prefer a “linear style” over a “tree style”. Use <code>goto</code> when it helps to make the code cleaner (e.g. for cleanup paths).</p>
  
 
'''Right:'''
 
'''Right:'''
Line 242: Line 264:
 
if (j == 1)
 
if (j == 1)
 
     return;
 
     return;
+
...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 255: Line 277:
 
         if (func3())
 
         if (func3())
 
         {
 
         {
            
+
             ...
 
         }
 
         }
 
     }
 
     }
Line 266: Line 288:
 
<ol>
 
<ol>
 
<li><p>Capitalize names of variables and functions.<br />
 
<li><p>Capitalize names of variables and functions.<br />
[[Hungarian Notation]] may be used when developing for Win32, but it is not required. If you don’t use it, the first letter of a name must be a capital too (no camelCase). Do not use underscores as separators either.</p>
+
[[Hungarian Notation]] may be used when developing for Win32, but it is not required. If you don’t use it, the first letter of a name must be a capital too (no lowerCamelCase). Do not use underscores as separators either.</p>
  
 
'''Right:'''
 
'''Right:'''
Line 310: Line 332:
 
/* This is a C-style comment */
 
/* This is a C-style comment */
  
//
 
 
// This is a comment over multiple lines.
 
// This is a comment over multiple lines.
 
// We don’t define any strict rules for it.
 
// We don’t define any strict rules for it.
//
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 331: Line 351:
 
<li>Win32/NT Boolean values should be written as <code>TRUE</code> and <code>FALSE</code>.<br />
 
<li>Win32/NT Boolean values should be written as <code>TRUE</code> and <code>FALSE</code>.<br />
 
In the rare case that you use C/C++ <code>bool</code> variables, you should write them as <code>true</code> and <code>false</code>.</li>
 
In the rare case that you use C/C++ <code>bool</code> variables, you should write them as <code>true</code> and <code>false</code>.</li>
 +
<li>When you need to terminate ANSI or OEM string, or check for its terminator, use <code>ANSI_NULL</code>. If the string is Unicode or Wide string, use <code>UNICODE_NULL</code>.
 
</ol>
 
</ol>
  
Line 336: Line 357:
 
* Never totally reformat a file and put a code change into it. Do this in separate commits.
 
* Never totally reformat a file and put a code change into it. Do this in separate commits.
 
* If a commit only consists of formatting changes, say this clearly in the commit message by preceding it with ''[FORMATTING]''.
 
* If a commit only consists of formatting changes, say this clearly in the commit message by preceding it with ''[FORMATTING]''.
 +
 +
== Other points ==
 +
* Do not use <code>LARGE_INTEGER</code>/<code>ULARGE_INTEGER</code> unless needed for using APIs. Use <code>INT64</code>/<code>UINT64</code> instead
 +
* Use <code>#pragma once</code> instead of guard defines in headers
 +
* Don't specify a calling convention for a function unless required (usually for APIs or exported symbols)
  
 
== Using an automatic code style tool ==
 
== Using an automatic code style tool ==
Line 343: Line 369:
 
Additional ideas were suggested during the discussion of this document, but a consensus couldn't be reached on them. Therefore we refrain from enforcing any rules on these points:
 
Additional ideas were suggested during the discussion of this document, but a consensus couldn't be reached on them. Therefore we refrain from enforcing any rules on these points:
 
* TO BE ADDED BY [[User:Hbelusca]]
 
* TO BE ADDED BY [[User:Hbelusca]]
 +
 +
== See also ==
 +
* [[Kernel Coding Style]]
 +
* [[GNU Indent]]
  
 
[[Category:Development]]
 
[[Category:Development]]
 
[[Category:Documentation]]
 
[[Category:Documentation]]
 +
[[Category:Tutorial]]

Latest revision as of 14:06, 12 October 2023

This article describes general coding style guidelines, which should be used for new ReactOS code. These guidelines apply exclusively to C and C++ source files. The Members of ReactOS agreed on this document in the October 2013 meeting.

As much existing ReactOS code as possible should be converted to this style unless there are reasons against doing this (like if the code is going to be rewritten from scratch in the near future). See Notes on reformatting existing code for more details.

Code synchronized with other sources (like Wine) must not be rewritten. 3rd Party Files.txt and WINESYNC.txt files can be used for tracking synchronized files.

File Structure

  1. Every ReactOS source code file should include a file header like this:
    /*
     * PROJECT:     ReactOS Kernel
     * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
     * PURPOSE:     Does cool things like Memory Management
     * COPYRIGHT:   Copyright 2017 Arno Nymous <abc@mailaddress.com>
     *              Copyright 2017 Mike Blablabla <mike@blabla.com>
     */
    

    Please use SPDX license identifiers available at https://spdx.org/licenses. This makes our source file parseable by licensing tools!

    You should add yourself to the COPYRIGHT section of a file if you did a major contribution to it and could take responsibility for the whole file or a part of it. Not more than 3 people shall be in that list for each file.

    FILE line of the old header should be removed.

  2. Doxygen documentation generator is used for ReactOS codebase, so use a proper header for functions, see API Documentation for details.

Indentation and line width

  1. Line width must be at most 100 characters.
  2. Do not add a space or tab at the end of any line.
  3. Indent with 4 spaces, don’t use tabs!
  4. Indent both a case label and the case statement of a switch statement.

    Right:

    switch (Condition)
    {
        case 1:
            DoSomething();
            break;
    
        case 2:
        {
            DoMany();
            ManyMore();
            OtherThings();
            break;
        }
    }
    

    Wrong:

    switch(Condition)
    {
    case 1:
         DoSomething();
         break;
    case 2:
        DoMany();
        ManyMore();
        OtherThings();
        break;
    }
    
  5. When a function call does not fit onto a line, align arguments like this:

    FunctionCall(arg1,
                 arg2,
                 arg3);
    
  6. Function headers should have this format (preserving the order as in the example):

    static // scope identifier
    CODE_SEG("PAGE") // section placement
    // other attributes
    BOOLEAN // return type
    FASTCALL // calling convention
    IsOdd(
        _In_ UINT32 Number);
    

Spacing

  1. Do not use spaces around unary operators.
    Right: i++;
    Wrong: i ++;
  2. Place spaces around binary and ternary operators.
    Right: a = b + c;
    Wrong: a=b+c;
  3. Do not place spaces before comma and semicolon.

    Right:

    for (int i = 0; i < 5; i++)
        DoSomething();
    
    func1(a, b);
    

    Wrong:

    for (int i = 0 ; i < 5 ; i++)
        DoSomething();
    
    func1(a , b) ;
    
  4. Place spaces between control statements and their parentheses.

    Right:

    if (Condition)
        DoSomething();
    

    Wrong:

    if(Condition)
        DoSomething();
    
  5. Do not place spaces between a function and its parentheses, or between a parenthesis and its content.

    Right:

    func(a, b);
    

    Wrong:

    func (a, b);
    func( a, b );
    

Line breaking

  1. Each statement should get its own line.

    Right:

    x++;
    y++;
    
    if (Condition)
        DoSomething();
    

    Wrong:

    x++; y++;
    
    if (Condition) DoSomething();
    

Braces

  1. Always put braces ({ and }) on their own lines.
  2. One-line control clauses may use braces, but this is not a requirement. An exception are one-line control clauses including additional comments.

    Right:

    if (Condition)
        DoSomething();
    
    if (Condition)
    {
        DoSomething();
    }
    
    if (Condition)
    {
        // This is a comment
        DoSomething();
    }
    
    if (A_Very || (Very && Long || Condition) &&
        On_Many && Lines)
    {
        DoSomething();
    }
    
    if (Condition)
        DoSomething();
    else
        DoSomethingElse();
    
    if (Condition)
    {
        DoSomething();
    }
    else
    {
        DoSomethingElse();
        YetAnother();
    }
    

    Wrong:

    if (Condition) {
        DoSomething();
    }
    
    if (Condition)
        // This is a comment
        DoSomething();
    
    if (A_Very || (Very && Long || Condition) &&
        On_Many && Lines)
        DoSomething();
    
    if (Condition)
        DoSomething();
    else
    {
        DoSomethingElse();
        YetAnother();
    }
    

Control structures

  1. Don’t use inverse logic in control clauses.
    Right: if (i == 1)
    Wrong: if (1 == i)
  2. Avoid too many levels of cascaded control structures. Prefer a “linear style” over a “tree style”. Use goto when it helps to make the code cleaner (e.g. for cleanup paths).

    Right:

    if (!func1())
        return;
    
    i = func2();
    if (i == 0)
        return;
    
    j = func3();
    if (j == 1)
        return;
    ...
    

    Wrong:

    if (func1())
    {
        i = func2();
        if (func2())
        {
            j = func3();
            if (func3())
            {
                ...
            }
        }
    }
    

Naming

  1. Capitalize names of variables and functions.
    Hungarian Notation may be used when developing for Win32, but it is not required. If you don’t use it, the first letter of a name must be a capital too (no lowerCamelCase). Do not use underscores as separators either.

    Right:

    PLIST_ENTRY FirstEntry;
    VOID NTAPI IopDeleteIoCompletion(PVOID ObjectBody);
    PWSTR pwszTest;
    

    Wrong:

    PLIST_ENTRY first_entry;
    VOID NTAPI iop_delete_io_completion(PVOID objectBody);
    PWSTR pwsztest;
    
  2. Avoid abbreviating function and variable names, use descriptive verbs where possible.
  3. Precede boolean values with meaningful verbs like "is" and "did" if possible and if it fits the usage.

    Right:

    BOOLEAN IsValid;
    BOOLEAN DidSendData;
    

    Wrong:

    BOOLEAN Valid;
    BOOLEAN SentData;
    

Commenting

  1. Avoid line-wasting comments, which could fit into a single line.

    Right:

    // This is a one-line comment
    
    /* This is a C-style comment */
    
    // This is a comment over multiple lines.
    // We don’t define any strict rules for it.
    

    Wrong:

    //
    // This comment wastes two lines
    //
    

Null, false and 0

  1. The null pointer should be written as NULL.
    In the rare case that your environment recommends a different null pointer (e.g. C++11 nullptr), you may use this one of course. Just don’t use the value 0.
  2. Win32/NT Boolean values should be written as TRUE and FALSE.
    In the rare case that you use C/C++ bool variables, you should write them as true and false.
  3. When you need to terminate ANSI or OEM string, or check for its terminator, use ANSI_NULL. If the string is Unicode or Wide string, use UNICODE_NULL.

Notes on reformatting existing code

  • Never totally reformat a file and put a code change into it. Do this in separate commits.
  • If a commit only consists of formatting changes, say this clearly in the commit message by preceding it with [FORMATTING].

Other points

  • Do not use LARGE_INTEGER/ULARGE_INTEGER unless needed for using APIs. Use INT64/UINT64 instead
  • Use #pragma once instead of guard defines in headers
  • Don't specify a calling convention for a function unless required (usually for APIs or exported symbols)

Using an automatic code style tool

TO BE ADDED BY User:Zefklop

Points deliberately left out

Additional ideas were suggested during the discussion of this document, but a consensus couldn't be reached on them. Therefore we refrain from enforcing any rules on these points:

See also