it-swarm.com.de

Können C-Präprozessor-Makros Präprozessor-Direktiven enthalten?

Ich möchte das Äquivalent von Folgendem tun:

#define print_max(TYPE) \
#  ifdef TYPE##_MAX \
     printf("%lld\n", TYPE##_MAX); \
#  endif

print_max(INT);

Jetzt ist der #ifdef oder eine verschachtelte Präprozessor-Direktive nicht erlaubt, soweit ich das in einem Funktionsmakro sehen kann. Irgendwelche Ideen?

Update: Das scheint also nicht möglich zu sein. Sogar ein Hack zur Laufzeit zu überprüfen scheint unerreichbar. Also denke ich, ich werde mit so etwas wie gehen:

#ifndef BLAH_MAX
#  define BLAH_MAX 0
#endif
# etc... for each type I'm interested in

#define print_max(TYPE) \
    if (TYPE##_MAX) \
       printf("%lld\n", TYPE##_MAX);

print_max(INT);
print_max(BLAH);
28
pixelbeat

Der Boost-Präprozessor (der sowohl für C als auch für C++ funktioniert, obwohl Boost insgesamt eine C++ - Bibliothek ist), kann bei dieser Art von Aufgabe hilfreich sein. Anstatt ein #ifdef in einem Makro zu verwenden (was nicht zulässig ist), hilft es Ihnen, eine Datei mehrmals einzufügen, wobei jedes Mal andere Makros definiert werden, sodass die Datei #ifdef verwenden kann.

Wenn der folgende Code in max.c gespeichert ist, sollte er für jedes der Wörter, die in der MAXES # -Definition oben in der Datei aufgeführt sind, das tun, was Sie möchten. Es funktioniert jedoch nicht, wenn einer der _MAX-Werte Fließkomma ist, da der Präprozessor Fließkomma nicht verarbeiten kann.

(Boost Processor ist ein praktisches Werkzeug, aber es ist nicht ganz einfach; Sie können entscheiden, ob dieser Ansatz eine Verbesserung gegenüber dem Kopieren und Einfügen darstellt.)

#define MAXES (SHRT)(INT)(LONG)(PATH)(DOESNT_EXIST)

#if !BOOST_PP_IS_ITERATING

/* This portion of the file (from here to #else) is the "main" file */

#include <values.h>
#include <stdio.h>
#include <boost/preprocessor.hpp>

/* Define a function print_maxes that iterates over the bottom portion of this
 * file for each Word in MAXES */
#define BOOST_PP_FILENAME_1 "max.c"
#define BOOST_PP_ITERATION_LIMITS (0,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(MAXES)))
void print_maxes(void) {
#include BOOST_PP_ITERATE()
}

int main(int argc, char *argv[])
{
    print_maxes();
}

#else

/* This portion of the file is evaluated multiple times, with
 * BOOST_PP_ITERATION() resolving to a different number every time */

/* Use BOOST_PP_ITERATION() to look up the current Word in MAXES */
#define CURRENT BOOST_PP_SEQ_ELEM(BOOST_PP_ITERATION(), MAXES)
#define CURRENT_MAX BOOST_PP_CAT(CURRENT, _MAX)

#if CURRENT_MAX
printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is %lld\n", (long long) CURRENT_MAX);
#else
printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is undefined\n");
#endif

#undef CURRENT
#undef CURRENT_MAX

#endif
12
Josh Kelley

Ich habe das schon mal probiert. Das Problem ist, dass # bereits für die Stringisierung eines Makroparameters reserviert ist. Es wird nicht als Präprozessor-Token wie in #define analysiert.

Die einzige Lösung, die ich habe, ist das Schummeln. Erstellen Sie eine Liste von Typen, die _XXX_MAX als Gruppe von definierten Werten haben, und verwenden Sie diese dann. Ich weiß nicht, wie ich die Liste auf automatisierte Weise im Preprozessor erstellen kann, also versuche ich es nicht. Die Annahme ist, dass die Liste nicht zu lang ist und nicht zu intensiv gepflegt wird.

#define PRINT_MAX(type) printf("%lld\n", _TYPE##_MAX);
#define HAVE_MAX(type) _TYPE##_MAX // not sure if this works 


/* a repetitious block of code that I cannot factor out - this is the cheat */
#ifdef HAVE_MAX(INT)
#define PRINT_INT_MAX PRINT_MAX(INT)
#endif

#ifdef HAVE_MAX(LONG)
#define PRINT_LONG_MAX PRINT_MAX(LONG)
#endif
/* end of cheat */


#define print_max(type) PRINT_##TYPE##_MAX
4
Arkadiy

Im Gegensatz zu Vorlagen ist der Präprozessor nicht turing-complete . Ein #ifdef innerhalb eines Makros ist nicht möglich. Ihre einzige Lösung besteht darin, sicherzustellen, dass Sie print_max nur für Typen aufrufen, für die ein übereinstimmender _MAX definiert ist, z. INT_MAX. Der Compiler wird Ihnen sicherlich sagen, wenn dies nicht der Fall ist.

0

Sofern Sie nur an ganzzahligen Werten interessiert sind und die Hardware mit 2er-Kompliment und 8-Bit-Bytes angenommen wird:

// Of course all this MAX/MIN stuff assumes 2's compilment, with 8-bit bytes...

#define LARGEST_INTEGRAL_TYPE long long

/* This will evaluate to TRUE for an unsigned type, and FALSE for a signed
 * type.  We use 'signed char' since it should be the smallest signed type
 * (which will sign-extend up to <type>'s size) vs. possibly overflowing if
 * going in the other direction (from a larger type to a smaller one).
 */
#define ISUNSIGNED(type) (((type) ((signed char) -1)) > (type) 0)

/* We must test for the "signed-ness" of <type> to determine how to calculate
 * the minimum/maximum value.
 *
 * e.g., If a typedef'ed type name is passed in that is actually an unsigned
 * type:
 *
 *  typedef unsigned int Oid;
 *  MAXIMUM_(Oid);
 */
#define MINIMUM_(type)  ((type) (ISUNSIGNED(type) ? MINIMUM_UNSIGNED_(type)   \
                              : MINIMUM_SIGNED_(  type)))

#define MAXIMUM_(type)  ((type) (ISUNSIGNED(type) ? MAXIMUM_UNSIGNED_(type)   \
                          : MAXIMUM_SIGNED_(  type)))

/* Minumum unsigned value; zero, by definition -- we really only have this
 * macro for symmetry.
 */
#define MINIMUM_UNSIGNED_(type)     ((type) 0)

// Maximum unsigned value; all 1's.
#define MAXIMUM_UNSIGNED_(type)         \
     ((~((unsigned LARGEST_INTEGRAL_TYPE) 0))   \
      >> ((sizeof(LARGEST_INTEGRAL_TYPE) - sizeof(type)) * 8))

/* Minimum signed value; a 1 in the most-significant bit.
 *
 * We use LARGEST_INTEGRAL_TYPE as our base type for the initial bit-shift
 * because we should never overflow (i.e., <type> should always be the same
 * size or smaller than LARGEST_INTEGRAL_TYPE).
 */
#define MINIMUM_SIGNED_(type)       \
  ((type)               \
   ((signed LARGEST_INTEGRAL_TYPE)  \
    (~((unsigned LARGEST_INTEGRAL_TYPE) 0x0) << ((sizeof(type) * 8) - 1))))

// Maximum signed value; 0 in most-significant bit; remaining bits all 1's.
#define MAXIMUM_SIGNED_(type)       (~MINIMUM_SIGNED_(type))
0
Gary H

Es gibt keinen einfachen Weg, dies zu tun. Am nächsten ist es, eine große Anzahl von IFDEF-Makros zu definieren:

#undef IFDEF_INT_MAX
#ifdef INT_MAX
#define IFDEF_INT_MAX(X)  X
#else
#define IFDEF_INT_MAX(X)
#endif

#undef IFDEF_BLAH_MAX
#ifdef BLAH_MAX
#define IFDEF_BLAH_MAX(X)  X
#else
#define IFDEF_BLAH_MAX(X)
#endif

     :

da Sie viele davon benötigen (und sie könnten an mehreren Stellen nützlich sein), ist es sehr sinnvoll, all diese Informationen in ihrer eigenen Header-Datei 'ifdefs.h' zu speichern, die Sie jederzeit einfügen können . Sie können sogar ein Skript schreiben, das ifdef.h aus einer Liste von 'Makros von Interesse' neu generiert.

Dann wird Ihr Code

#include "ifdefs.h"
#define print_max(TYPE) \
IFDEF_##TYPE##_MAX( printf("%lld\n", TYPE##_MAX); )

print_max(INT);
print_max(BLAH);
0
Chris Dodd

Ich glaube nicht, dass der Operator ## in #ifdef nicht erlaubt ist. Ich habe das versucht:

#define _print_max(TYPE) \
#ifdef TYPE \
printf("%lld\n", _TYPE); \
#endif

#define print_max(TYPE) _print_max(MAX##_TYPE)


void main() 
{
    print_max(INT)
}

und es hat immer noch nicht funktioniert (#ifdef TYPE hat es nicht gefallen). Das Problem ist, dass #ifdef nur #definierte Symbole akzeptiert, nicht #define-Argumente. Das sind zwei verschiedene Dinge.

0
Ferruccio