Erweiterte C-Makros sehen

Lesezeit: 7 Minuten

hasens Benutzeravatar
Hasen

Wenn ich ein C-Makro erweitern möchte, was sind einige gute Möglichkeiten, dies zu tun (außer dem manuellen Verfolgen)?

Zum Beispiel, GTK_WIDGET_SET_FLAGSes verwendet ein Makro, das ein Makro verwendet, das ein Makro (oder zwei) verwendet …

Ich möchte es nur irgendwie automatisch erweitert sehen, anstatt bei jedem Schritt nach jedem Makro zu suchen.

AKTUALISIEREN

Ich habe es mit cpp versucht, aber es schien nur den ersten Durchgang zu machen

an:

GTK_WIDGET_SET_FLAGS(obj, 13)

Ich habe die Include-Datei erweitert und dann:

G_STMT_START{ ((GTK_OBJECT_FLAGS (obj)) |= (13)); }G_STMT_END

Dies wird durch diese Fehlermeldung erklärt. Ich bekomme dies auf stderr (bei Verwendung von -o Dateiname)

gtk/gtkwidget.h:34:21: gdk/gdk.h: No such file or directory
gtk/gtkwidget.h:35:31: gtk/gtkaccelgroup.h: No such file or directory
gtk/gtkwidget.h:36:27: gtk/gtkobject.h: No such file or directory
gtk/gtkwidget.h:37:31: gtk/gtkadjustment.h: No such file or directory
gtk/gtkwidget.h:38:26: gtk/gtkstyle.h: No such file or directory
gtk/gtkwidget.h:39:29: gtk/gtksettings.h: No such file or directory
gtk/gtkwidget.h:40:21: atk/atk.h: No such file or directory

Die Verzeichnisse gtk, atk und gdk befinden sich alle im aktuellen Arbeitsverzeichnis, also wie lasse ich cpp darin suchen?

Übrigens, gcc -E gibt genau die gleiche Ausgabe wie cpp

Update2:

Das Problem mit dem Include-Pfad wird gelöst, indem gcc -E verwendet und das Include-Verzeichnis mit der Option -I übergeben wird

  • Versuchen Sie, Cop auf Ihrer Quelldatei auszuführen.

    – Alex Braun

    12. Juni 2009 um 7:20 Uhr

  • Versuchen Sie nicht, cpp direkt zu verwenden – es hat eine Reihe von Fallstricken. Wie andere vorgeschlagen haben, verwenden Sie das Flag -E von gcc.

    anon

    12. Juni 2009 um 8:14 Uhr

  • Wie die Leute gesagt haben, verwenden Sie gcc. Außerdem müssen Sie, wie immer beim Erstellen mit GTK+, dem Compiler mitteilen, wo er die Include-Dateien finden kann. Für GTK+ geschieht dies mit pkg-config, etwa so: „gcc -E $(pkg-config –cflags gtk+-2.0) myfile.c“.

    – abschalten

    12. Juni 2009 um 9:30 Uhr

Je nachdem, welchen Compiler Sie verwenden, sollte es eine Möglichkeit geben, den Code nach dem zu sehen Präprozessor (das macht die Makroerweiterung, Makros kennt der Compiler überhaupt nicht) fertig.

Mit gcc ist die Option -E. Hier ist ein vereinfachtes Beispiel, das Spielzeugcode und nicht das eigentliche GTK+-Makro verwendet:

~/tmp> cat cpptest.c
#define SET_FLAGS(w, f) ((w)->flags |= (f))

int main(void)
{
        SET_FLAGS(0, 4711);

        return 0;
}
~/tmp> gcc -E cpptest.c
# 1 "cpptest.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "cpptest.c"


int main(void)
{
 ((0)->flags |= (4711));

 return 0;
}

  • Wichtiger Hinweis: Sie müssen gcc auch die gleichen -I-Flags übergeben, die Sie während der normalen Kompilierung verwenden würden, damit es die richtigen Header-Dateien finden kann.

    – Adam Rosenfield

    12. Juni 2009 um 15:38 Uhr

  • Sie können verwenden -E -dD um Makrodefinitionen in die Ausgabe aufzunehmen.

    – Gerald Kämme

    19. Mai 2011 um 23:55 Uhr

  • Für POSIX-Systeme ohne Gcc: POSIX spezifiziert beides -E und -I zum c99.

    – Mafso

    28. September 2014 um 12:57 Uhr

  • In meinem Fall enthält die Ausgabe immer noch Makros. Wissen Sie, ob wir es erweitern können, bis alle Makros entfernt sind?

    – yuefengz

    27. Oktober 2014 um 0:18 Uhr

Benutzeravatar von Cătălin Pitiș
Cătălin Pitiș

In Visual Studio können Sie die aus dem Präprozessor resultierende Übersetzungseinheitsdatei generieren. Sie können zu den Projektoptionen, C/C++/Preprocessor gehen und “Vorverarbeitete Datei generieren” oder “In eine Datei vorverarbeiten” auf Ja setzen (oder /P oder /EP-Compilerschalter verwenden, um Zeilennummern einzuschließen oder nicht).

Sie können die Erweiterung eines Makros zur Laufzeit wie folgt ausgeben:

#include <stdio.h>

/*
 * generic helper macros
 */
#define CALL(macro, arguments) macro arguments
#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) # __VA_ARGS__

/*
 * dumps a macro and its expansion to stdout
 * the second argument is optional and specifies the number of
 * arguments that macro takes: 0 means macro takes zero arguments
 * no second argument means macro is not function-like
 */
#define DUMP_MACRO(macro, ...) \
    do { \
        puts ( \
            "'" \
            # macro STR(DUMP_MACRO_ARGS_ ## __VA_ARGS__) \
            "' expands to '" \
            STR(CALL(macro, DUMP_MACRO_ARGS_ ## __VA_ARGS__)) \
            "'" \
        ); \
    } while (0)
/* helpers for DUMP_MACRO, add more if required */
#define DUMP_MACRO_ARGS_
#define DUMP_MACRO_ARGS_0 ()
#define DUMP_MACRO_ARGS_1 (<1>)
#define DUMP_MACRO_ARGS_2 (<1>, <2>)
#define DUMP_MACRO_ARGS_3 (<1>, <2>, <3>)

/*
 * macros to be used in examples for DUMP_MACRO
 */
#define EXAMPLE ( EXAMPLE0() << 9 )
#define EXAMPLE0() __GNUC__
#define EXAMPLE1(EXAMPLE1) EXAMPLE1
#define EXAMPLE3(EXAMPLE1, _, __) ( EXAMPLE1 ? _(__) : false )

int main() {
    /* examples */
    DUMP_MACRO(EXAMPLE);
    DUMP_MACRO(EXAMPLE0, 0);
    DUMP_MACRO(EXAMPLE1, 1);
    DUMP_MACRO(EXAMPLE3, 3);
    DUMP_MACRO(EXAMPLE3(EXAMPLE, EXAMPLE1, non_macro_symbol));
    /* does not work for DUMP_MACRO itself, because the
       preprocessor does not allow recursion */
    DUMP_MACRO(DUMP_MACRO, 1);
    DUMP_MACRO(DUMP_MACRO, 2);
    return 0;
}

Das Programm druckt:

'EXAMPLE' expands to '( 4 << 9 )'
'EXAMPLE0()' expands to '4'
'EXAMPLE1(<1>)' expands to '<1>'
'EXAMPLE3(<1>, <2>, <3>)' expands to '( <1> ? <2>(<3>) : false )'
'EXAMPLE3(EXAMPLE, EXAMPLE1, non_macro_symbol)' expands to '( ( 4 << 9 ) ? non_macro_symbol : false )'
'DUMP_MACRO(<1>)' expands to 'DUMP_MACRO (<1>)'
'DUMP_MACRO(<1>, <2>)' expands to 'DUMP_MACRO (<1>, <2>)'

Dies ergibt jedoch nur die voll Erweiterung. Wenn Sie einzelne Schritte benötigen, kann Eclipse/CDT helfen, aber nur, wenn Sie ihm alle Header und Compiler-Flags beibringen, die Sie verwenden.

gcc -E myfile.c

gcc benötigt auch mit -E den Pfad der Header-Dateien … wie -I _path_to_your_headers …

Wenn Sie ein Makefile haben, können Sie im Allgemeinen CC mit gcc -E überschreiben

Im Allgemeinen ist cpp nur ein Skript, das gcc einige Flags für den Präprozessor hinzufügt, wie traditionell …

Ciro Santilli Benutzeravatar von OurBigBook.com
Ciro Santilli OurBigBook.com

GCC -save-temps

Der große Vorteil dieser Option gegenüber -E ist, dass es sehr einfach zu jedem Build-Skript hinzugefügt werden kann, ohne viel in den Build selbst einzugreifen.

Wenn Sie das tun:

gcc -save-temps -c -o main.o main.c

Haupt c

#define INC 1

int myfunc(int i) {
    return i + INC;
}

und jetzt neben der normalen Ausgabe main.oenthält das aktuelle Arbeitsverzeichnis außerdem die folgenden Dateien:

  • main.i ist a enthält die gewünschte vorverarbeitete Datei:

    # 1 "main.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 31 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 32 "<command-line>" 2
    # 1 "main.c"
    
    
    int myfunc(int i) {
        return i + 1;
    }
    
  • main.s ist ein Bonus und enthält die gewünschte generierte Assembly:

        .file   "main.c"
        .text
        .globl  myfunc
        .type   myfunc, @function
    myfunc:
    .LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        addl    $1, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
    .LFE0:
        .size   myfunc, .-myfunc
        .ident  "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
        .section    .note.GNU-stack,"",@progbits
    

Wenn Sie dies für eine große Anzahl von Dateien tun möchten, sollten Sie stattdessen Folgendes verwenden:

 -save-temps=obj

Dadurch werden die Zwischendateien im selben Verzeichnis wie die gespeichert -o Objektausgabe anstelle des aktuellen Arbeitsverzeichnisses, wodurch potenzielle Basisnamenkonflikte vermieden werden.

Eine weitere coole Sache an dieser Option ist, wenn Sie hinzufügen -v:

gcc -save-temps -c -o main.o -v main.c

Es zeigt tatsächlich die expliziten Dateien, die anstelle von hässlichen temporären Dateien verwendet werden /tmpso ist es einfach, genau zu wissen, was vor sich geht, einschließlich der Vorverarbeitungs- / Kompilierungs- / Montageschritte:

/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s

Getestet in Ubuntu 19.04 amd64, GCC 8.3.0.

Benutzeravatar von Michael Burr
Michael Burr

Viele IDEs zeigen Ihnen die erweiterte Version des Makros im Editor, wenn der Mauszeiger über den Bezeichner schwebt (oder auf andere Weise). Ich weiß, dass Eclipse/CDT dies tut, und Visual Studio tut dies (zumindest VS 2008).

Es kann nützlich sein, wenn der Compiler eine vorverarbeitete Ausgabe generiert, wenn Sie ein kniffliges Problem aufspüren, aber für den täglichen Gebrauch, bei dem Sie nur wissen möchten, was mit dem Code auf Ihrem Bildschirm los ist, ist die Verwendung der IDE der richtige Weg gehen.

  • Mein VS 2008 erweitert das Makro beim Hover nicht. Muss ich diese Option irgendwo einschalten?

    – buti-oxa

    12. Juni 2009 um 21:47 Uhr

1416340cookie-checkErweiterte C-Makros sehen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy