Wie erstelle ich eine Zeichenkette aus dem Wert eines C-Makros?

Lesezeit: 4 Minuten

Benutzeravatar von jfs
jfs

Wie kann man zum Beispiel vermeiden, „func_name“ zweimal zu schreiben?

#ifndef TEST_FUN
#  define TEST_FUN func_name
#  define TEST_FUN_NAME "func_name"
#endif

Dem möchte ich folgen Einziger Punkt der Wahrheit Regel.

Version des C-Präprozessors:

$ cpp --version
cpp (GCC) 4.1.2 20070626 (Red Hat 4.1.2-14)

  • Mögliches Duplikat von C-Makros zum Erstellen von Zeichenfolgen

    – Richard Stelling

    6. Oktober 2015 um 10:34 Uhr

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Wer schüchtern ist* gab dir den Keim einer Antwort, aber nur den Keim. Die grundlegende Technik zum Konvertieren eines Werts in einen String im C-Präprozessor erfolgt zwar über den ‘#’-Operator, aber eine einfache Transliteration der vorgeschlagenen Lösung führt zu einem Kompilierungsfehler:

#define TEST_FUNC test_func
#define TEST_FUNC_NAME #TEST_FUNC

#include <stdio.h>
int main(void)
{
    puts(TEST_FUNC_NAME);
    return(0);
}

Der Syntaxfehler befindet sich in der ‘puts()’-Zeile – das Problem ist ein ‘verirrtes #’ in der Quelle.

In Abschnitt 6.10.3.2 des C-Standards „Der #-Operator“ heißt es:

Jedem # Vorverarbeitungstoken in der Ersetzungsliste für ein funktionsähnliches Makro soll ein Parameter als nächstes Vorverarbeitungstoken in der Ersetzungsliste folgen.

Das Problem ist, dass Sie Makroargumente in Zeichenfolgen konvertieren können – aber Sie können keine zufälligen Elemente konvertieren, die keine Makroargumente sind.

Um den gewünschten Effekt zu erzielen, müssen Sie also mit Sicherheit etwas zusätzliche Arbeit leisten.

#define FUNCTION_NAME(name) #name
#define TEST_FUNC_NAME  FUNCTION_NAME(test_func)

#include <stdio.h>

int main(void)
{
    puts(TEST_FUNC_NAME);
    return(0);
}

Mir ist nicht ganz klar, wie Sie die Makros verwenden und wie Sie Wiederholungen insgesamt vermeiden möchten. Dieses etwas ausführlichere Beispiel könnte informativer sein. Die Verwendung eines Makros, das STR_VALUE entspricht, ist ein Idiom, das erforderlich ist, um das gewünschte Ergebnis zu erzielen.

#define STR_VALUE(arg)      #arg
#define FUNCTION_NAME(name) STR_VALUE(name)

#define TEST_FUNC      test_func
#define TEST_FUNC_NAME FUNCTION_NAME(TEST_FUNC)

#include <stdio.h>

static void TEST_FUNC(void)
{
    printf("In function %s\n", TEST_FUNC_NAME);
}

int main(void)
{
    puts(TEST_FUNC_NAME);
    TEST_FUNC();
    return(0);
}

* Zu der Zeit, als diese Antwort zum ersten Mal geschrieben wurde, verwendete Shooshs Namen „Shy“ als Teil des Namens.

  • Es klappt. Vielen Dank. Ich habe ein funktionierendes Beispiel gepostet, das die Motivation für den Code widerspiegelt. stackoverflow.com/questions/195975/…

    – jfs

    12. Oktober 2008 um 21:13 Uhr

  • Fast wörtliche Neufassung eines Kommentars, der ursprünglich am 12.10.2012 um 21:37 Uhr abgegeben wurde (der eine fettgedruckte Funk Anstatt von __func__) — Natürlich könnten wir in C99 die verwenden __func__ vordefinierter Bezeichner in der Funktion für den Funktionsnamen. Außerhalb der Funktion ist dies jedoch keine Hilfe, und hier wird der Funktionsnamen-String wirklich benötigt.

    – Jonathan Leffler

    29. Dezember 2013 um 18:17 Uhr

  • Dein zweiter Code funktioniert bei mir nicht. Das test_func sollte ein Makro für den Fall von OP sein, denke ich. Wenn Sie #define test_func my_test_func. (wodurch test_func ein Makro wird), es wird immer noch gedruckt test_func nicht my_test_func.

    – Chan-Kim

    6. November 2017 um 1:31 Uhr

  • @ChanKim: Kannst du zeigen, was nicht funktioniert? Wenn nötig (wenn es nicht vernünftig in einen Kommentar passt), kontaktieren Sie mich per E-Mail – siehe mein Profil.

    – Jonathan Leffler

    6. November 2017 um 7:29 Uhr

  • @JonathanLeffler Hallo, ich habe dir eine E-Mail geschickt. Wir brauchen eine zweistufige Makrosubstitution. siehe stackoverflow.com/questions/3419332/…

    – Chan-Kim

    7. November 2017 um 2:00 Uhr

@Jonathan Leffler: Danke. Deine Lösung funktioniert.

Ein vollständiges Arbeitsbeispiel:

/** compile-time dispatch 

   $ gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub
*/
#include <stdio.h>

#define QUOTE(name) #name
#define STR(macro) QUOTE(macro)

#ifndef TEST_FUN
#  define TEST_FUN some_func
#endif

#define TEST_FUN_NAME STR(TEST_FUN)

void some_func(void)
{
  printf("some_func() called\n");
}

void another_func(void)
{
  printf("do something else\n");
}

int main(void)
{
  TEST_FUN();
  printf("TEST_FUN_NAME=%s\n", TEST_FUN_NAME);
  return 0;
}

Beispiel:

$ gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub
do something else
TEST_FUN_NAME=another_func

#include <stdio.h>

#define QUOTEME(x) #x

#ifndef TEST_FUN
#  define TEST_FUN func_name
#  define TEST_FUN_NAME QUOTEME(TEST_FUN)
#endif

int main(void)
{
    puts(TEST_FUN_NAME);
    return 0;
}

Referenz: Wikipedias C-Präprozessor Seite

#define TEST_FUN_NAME #FUNC_NAME

sehen hier

1411530cookie-checkWie erstelle ich eine Zeichenkette aus dem Wert eines C-Makros?

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

Privacy policy