web-dev-qa-db-fra.com

Est-ce que le format clang peut casser mon code?

Étant donné que clang-format est un outil permettant uniquement de reformater le code, est-il possible qu'un tel formatage permette de casser le code qui fonctionne ou au moins de changer son fonctionnement? Existe-t-il un type de contrat qui modifie/empêche le fonctionnement du code?

Nous souhaitons formater beaucoup de code avec clang-format. Cela signifie que beaucoup de lignes de code vont changer. Ne pas avoir à examiner chaque ligne de code qui a seulement changé en raison d'un clang-format simplifierait grandement ce processus.

Je dirais que clang-format ne changera pas le fonctionnement du code. Par contre, je ne suis pas sûr à 100%, si cela peut être garanti.

23
JFB

Réponse courte: OUI.


L'outil clang-format a une option -sort-includes. Changer l'ordre des directives #include peut définitivement changer le comportement du code existant, etpeut casser le code existant.

Puisque l'option SortIncludes correspondante est définie sur true par plusieurs des styles intégrés, il n'est peut-être pas évident que clang-format va réorganiser vos inclus.

MyStruct.h:

struct MyStruct {
    uint8_t value;
};

original.c:

#include <stdint.h>
#include <stddef.h>
#include "MyStruct.h"

int main (int argc, char **argv) {
    struct MyStruct s = { 0 };
    return s.value;
}

Maintenant, supposons que nous exécutons clang-format -style=llvm original.c > restyled.c.

restyled.c:

#include "MyStruct.h"
#include <stddef.h>
#include <stdint.h>

int main(int argc, char **argv) {
  struct MyStruct s = {0};
  return s.value;
}

En raison de la réorganisation des fichiers d'en-tête, j'obtiens le message d'erreur suivant lors de la compilation de restyled.c:

In file included from restyled.c:1:
./MyStruct.h:2:5: error: unknown type name 'uint8_t'
    uint8_t value;
    ^
1 error generated.

Cependant, ce problème devrait être facile à résoudre. Il est peu probable que vous ayez des inclusions dépendantes de l'ordre, mais si vous le faites, vous pouvez résoudre le problème en insérant une ligne vide entre les groupes d'en-têtes nécessitant un ordre spécifique, car apparemment clang-format ne trie que les groupes de directives #include sans #include lignes entre les deux.

fixed-original.c:

#include <stdint.h>
#include <stddef.h>

#include "MyStruct.h"

int main (int argc, char **argv) {
    struct MyStruct s = { 0 };
    return s.value;
}

fixed-restyled.c:

#include <stddef.h>
#include <stdint.h>

#include "MyStruct.h"

int main(int argc, char **argv) {
  struct MyStruct s = {0};
  return s.value;
}

Notez que stdint.h et stddef.h étaient toujours réorganisés car leurs inclusions sont toujours "groupées", mais que la nouvelle ligne vide empêchait MyStruct.h d'être déplacé avant la bibliothèque standard.


Toutefois...

Si la réorganisation de vos directives #include rompt votre code, vous devriez probablement effectuer l'une des opérations suivantes:

  1. Incluez explicitement les dépendances de chaque en-tête dans le fichier d'en-tête. Dans mon exemple, je devrais inclure stdint.h dans MyStruct.h.

  2. Ajoutez une ligne de commentaire entre les groupes d'inclusion qui énonce explicitement la dépendance de commande. Rappelez-vous que toute ligne non -#include doit séparer un groupe, les lignes de commentaires fonctionnent donc également. La ligne de commentaire dans le code suivant empêche également clang-format d'inclure MyStruct.h avant les en-têtes de bibliothèque standard.

alternate-original.c:

#include <stdint.h>
#include <stddef.h>
// must come after stdint.h
#include "MyStruct.h"

int main (int argc, char **argv) {
    struct MyStruct s = { 0 };
    return s.value;
}
41
DaoWen

Bien sûr, cela peut changer le fonctionnement de votre code. Et la raison en est que le programme C peut afficher certaines propriétés de son code source. Je pense à la macro __LINE__, mais je ne suis pas sûre qu'il n'y ait pas d'autre moyen.

Considérez 1.c:

#include <stdio.h>
int main(){printf("%d\n", __LINE__);}

Ensuite:

> clang 1.c -o 1.exe & 1.exe
2

Maintenant, faites quelques clang-format:

> clang-format -style=Chromium 1.c >2.c

Et 2.c est:

#include <stdio.h>
int main() {
  printf("%d\n", __LINE__);
}

Et bien sûr, la sortie a changé:

> clang 2.c -o 2.exe & 2.exe
3
6
deniss

Étant donné que clang-format n'affecte que les caractères d'espacement, vous pouvez vérifier que les fichiers avant et après clang-formating sont identiques aux espaces. Sous Linux/BSD/OS X, vous pouvez utiliser diff et tr pour cela:

$ diff --ignore-all-space <(tr '\n' ' ' < 2.c ) <(tr '\n' ' ' < 1.c)

1.c:

#include <stdio.h>
int main() {printf("Hello, world!\n"); return 0;}

2.c:

#include <stdio.h>
int main() {
    printf("Hello, world!\n");
    return 0;
}

La sortie de la commande diff est vide, ce qui signifie que les fichiers 1.c et 2.c sont identiques jusqu’à des espaces.

En tant que Karoly mentionné dans son commentaire, notez que dans des conditions idéales, vous devez toujours vérifier les espaces qui comptent, par exemple. littéraux de chaîne. Mais dans le monde réel, je pense que ce test est largement suffisant.

4
Anton K

Oui

il ne sera pas briser le flux de travail

le système dispose du commutateur de configuration: "C_Cpp.clang_format_sortIncludes": false ,

ma version est: ms-vscode.cpptools-0.13.1

c'est ma solution:

pour le flux de travail stable, utilisez la grammaire:

// format-off désactivé

... voici votre code

// format clang sur

1
hiproz

le code ASM reformaté au format clang dans un projet parce que nous avons effectivement fait ceci:

#define ASM _asm

ASM {

  ...

}
0
pdc