Most POSIX-compatible systems provide a function to get or set one of high-resolution timers:
int clock_gettime(clockid_t clock_id, struct timespec *tp);
Documentation for each system usually lists several symbolic names as possible clock_id values, but actual numeric values are never mentioned. It turns out that not only the numeric values are different across various systems, but symbolic names are also not the same for the same meaning. Even more so, not all the clocks actually supported by a system are defined in time.h (bits/time.h) — some are only defined in, let's say, linux/time.h.
That is, in a Linux system we may have:
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
#define CLOCK_PROCESS_CPUTIME_ID 2
#define CLOCK_THREAD_CPUTIME_ID 3
#define CLOCK_MONOTONIC_RAW 4
#define CLOCK_REALTIME_COARSE 5
#define CLOCK_MONOTONIC_COARSE 6
#define CLOCK_BOOTTIME 7
#define CLOCK_REALTIME_ALARM 8
#define CLOCK_BOOTTIME_ALARM 9
#define CLOCK_SGI_CYCLE 10 // In linux/time.h only.
#define CLOCK_TAI 11 // In linux/time.h only.
In Cygwin environment (not a verbatim excerpt):
#define CLOCK_REALTIME 1 // Means CLOCK_MONOTONIC?
#define CLOCK_MONOTONIC 4 // Means CLOCK_MONOTONIC_RAW?
#define CLOCK_PROCESS_CPUTIME_ID 2
#define CLOCK_THREAD_CPUTIME_ID 3
In FreeBSD:
#define CLOCK_REALTIME 0
#define CLOCK_VIRTUAL 1
#define CLOCK_PROF 2
#define CLOCK_MONOTONIC 4
#define CLOCK_UPTIME 5 // Synonymous to CLOCK_BOOTTIME?
#define CLOCK_UPTIME_PRECISE 7
#define CLOCK_UPTIME_FAST 8
#define CLOCK_REALTIME_PRECISE 9 // Same as CLOCK_REALTIME?
#define CLOCK_REALTIME_FAST 10 // Synonymous to CLOCK_REALTIME_COARSE?
#define CLOCK_MONOTONIC_PRECISE 11 // Same as CLOCK_MONOTONIC?
#define CLOCK_MONOTONIC_FAST 12 // Synonymous to CLOCK_MONOTONIC_COARSE?
#define CLOCK_SECOND 13
#define CLOCK_THREAD_CPUTIME_ID 14
#define CLOCK_PROCESS_CPUTIME_ID 15
In AIX:
#define CLOCK_REALTIME ...
#define CLOCK_MONOTONIC ...
#define CLOCK_PROCESS_CPUTIME_ID ...
#define CLOCK_THREAD_CPUTIME_ID ...
In SunOS:
#define CLOCK_REALTIME ...
#define CLOCK_HIGHRES ... // Synonymous to CLOCK_MONOTONIC_RAW?
In QNX:
#define CLOCK_REALTIME ...
#define CLOCK_SOFTTIME ...
#define CLOCK_MONOTONIC ...
And so on.
This makes me wonder how to use clock_gettime() with the first argument other than CLOCK_REALTIME in a portable way. For example, if I want to use CLOCK_MONOTONIC_COARSE or CLOCK_BOOTTIME, how do I know that BSD calls them CLOCK_MONOTONIC_FAST and CLOCK_UPTIME, respectively, instead?
Is it wise to make assumptions based on numeric values of the first 4 symbolic names? Such as:
#define POSIX_CLOCK_REALTIME 0
#define POSIX_CLOCK_MONOTONIC 1
#define POSIX_CLOCK_PROCESS_CPUTIME_ID 2
#define POSIX_CLOCK_THREAD_CPUTIME_ID 3
#define POSIX_CLOCK_MONOTONIC_RAW 4
#if CLOCK_REALTIME == POSIX_CLOCK_MONOTONIC
#warning This platform has monotonic realtime clock.
#end if
#if CLOCK_MONOTONIC == POSIX_CLOCK_MONOTONIC_RAW
#warning This platform has undisciplined monotonic clock.
#end if
If a system actually supports CLOCK_TAI but does not define it in time.h, how can I check and use that, taking into account that the same numeric value 11 may stand for CLOCK_MONOTONIC_PRECISE or whatever in other systems?
If I was trying to write a maximally-portable program, I would limit myself to the symbolic values defined in the relevant Standard. (From what you say, it sounds like CLOCK_REALTIME -- and perhaps only that value -- is standard.)
If some systems implement useful extensions that I wanted to use, I would test for them by saying
#ifdef CLOCK_MONOTONIC_COARSE
... my code calling clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) ...
#endif
And if it's really true that there are systems out there where the same symbolic values end up meaning distinctly different things, I would throw up my hands and declare that to be a portability nightmare, the kind that I, at least, try to stay far away from.
In answer to your other questions, (1) no, it's not wise to make assumptions about the symbolic values, and (2) there's no good way to use a clock that somehow does exist but is not defined in time.h (though this situation would hopefully be quite rare).
Also, are you assuming that just because the numeric value 1 is used for CLOCK_MONOTONIC on Linux but for CLOCK_REALTIME under Cygwin means that those clocks might somehow be the same? That's probably not the case. The numbers are arbitrary and you shouldn't care about them; that's why the symbolic constants exist!
Related
I'm wondering if it can be written that the prepocessor evaluates assigned constants known at compile time and returns the result as a string. I believe the answer is no or complex, but I'll give a try.
Basically I have constants which are expressed in milliseconds but I want to display the results as secs, therefore divide by 1000, and wonder because all is known at compile time, if the preprocessor can directly put the result of this division into the code rather than eval at runtime.
Example:
#define FREQ_AUTO_WHEN_RELAY_ON 150000UL
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
STR( FREQ_AUTO_WHEN_RELAY_ON/1000UL ) " secs"
would yield to "150000UL/1000UL secs"
which is not I want to display, aka "150 secs"
Thanks
You have to first prepare a header with all possible outputs:
// calculate.h
#if VALUE == 1
#define RESULT 1
#elif VALUE == 2
#define RESULT 2
/* etc. millions of lines */
#elif VALUE == 150
#define RESULT 150
#endif
Then you can do:
#define VALUE FREQ_AUTO_WHEN_RELAY_ON/1000UL
#include "calculate.h"
STR(VALUE)
Similarly, you first have to define a matrix of all possible combinations of values:
#define DIV_1UL_1UL 1
#define DIV_1UL_2UL 0
#define DIV_2UL_1UL 2
/* etc. really millions of lines */
#define DIV_150000UL_1000UL 150
Then you can:
#define DIV(a, b) DIV_##a##_##b
#define XDIV(a, b) DIV(a, b)
STR(XDIV(FREQ_AUTO_WHEN_RELAY_ON, 1000UL))
Can C-preprocessor can output as a string the evaluation of compiled known constants values(e.g. 150000UL/1000UL)?
Yes, but it's not practical. Instead, generate the header file from a build system.
My machine has CRTSCTS #defined inside a #ifdef __USE_MISC which stops it being available to C programs which I compile.
/usr/include/x86_64-linux-gnu/bits/termios.h:
...
#define B4000000 0010017
#define __MAX_BAUD B4000000
#ifdef __USE_MISC
# define CIBAUD 002003600000 /* input baud rate (not used) */
# define CMSPAR 010000000000 /* mark or space (stick) parity */
# define CRTSCTS 020000000000 /* flow control */
#endif
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
...
How do I get access to CRTSCTS without just hacking the value 020000000000 into my program?
I already #include <termios.h> and many other headers.
I am also using:
#define __USE_POSIX199309
#define _POSIX_C_SOURCE 199309L
#include <time.h> /* nanosleep needs lines above */
The __USE_MISC macro is an internal definition that, though I suppose you could define this yourself, it's better to find the proper feature-test macro that enables it.
On my CentOS 7 system, /usr/include/features.h has a whole range of these kinds of macros, and it appears that __USE_MISC is enabled by _BSD_SOURCE or _SVID_SOURCE; it's not clear which one is compatible with other things you're going to need.
... // features.h
#if defined _BSD_SOURCE || defined _SVID_SOURCE
# define __USE_MISC 1
#endif
Try #define _BSD_SOURCE at the top of your program - before all the includes - and see how it goes.
Ref: http://man7.org/linux/man-pages/man7/feature_test_macros.7.html
The problem:
I'm writing a general C library for an LCD in a microcontroller project.
up to 8 LCDs with various sizes(e.g. 128*96 or 64*48) in various addresses may be added (e.g. LCD3 and LCD7). but only one of them is actively coded at a time. so I thought for a mechanism to do so.
in the code, there is a definition for CLCD_ROWS and CLCD_COLS which correspond to the Active display size.
#define CLCD_ROWS // Active LCD rows
#define CLCD_COLS // Active LCD columns
and there's definitions for the various LCDs. for example, if we have LCD3 and LCD7 connected, we define their sizes with :
#define CLCD_ROWS3 96
#define CLCD_COLS3 64
#define CLCD_ROWS7 128
#define CLCD_COLS7 32
The question:
I've written a [wrong] macro to redefine the values of CLCD_ROWS and CLCD_COLS :
#define cLcd_setActiveI2CcLcd(X) \
CLCD_ROWS = CLCD_ROWS##X \
CLCD_COLS = CLCD_COLS##X
and in my main code I call the macro:
cLcd_setActiveI2CcLcd(7);
which gives me an error of "missing ;".
it is easy to implement it with variables. but since these values are hardcoded , I thought they are "preprocessable" since need every bit of RAM in a low end MCU.
Is my approach about preprocessing this values, correct ?
What is the right way to write a macro for that purpose ?
I'm using a C99 compiler.
First things first, your method of using function-type macro is wrong. Even if you fix the error you have, the macro will not do CLCD_ROWS equal to CLCD_ROWS7, but to CLCD_ROWSX (that is how macros work, it concatenates the thing you give, not its value). Instead if you want to use macros for reducing RAM usage you can change your code to:
1st Solution
#define ROW_COLS 7 // change this if you use different display
#if ROW_COLS == 7
#define CLCD_ROWS 128
#define CLCD_COLS 32
#elif ROW_COLS == 3
#define CLCD_ROWS 96
#define CLCD_COLS 64
#endif
2nd Solution
If you want dynamically change the size of your display in the runtime, you can do it like this:
static int display_cnt;
#define CLCD_ROWS ((display_cnt == 3) ? 96 : 128)
#define CLCD_COLS ((display_cnt == 3) ? 64 : 32)
So when you change the value of display_cnt variable, the macro will automatically change its value.
I'm trying to write a portable program that deals with ustar archives. For device files, these archives store the major and minor device numbers. However, the struct stat as laid out in POSIX only contains a single st_rdev member of type dev_t described with “Device ID (if file is character or block special).”
How can I convert between a pair of major and minor device numbers and a single st_rdev member as returned by stat() in a portable manner?
While all POSIX programming interfaces use the device number (of type dev_t) as is, FUZxxl pointed out in a comment to this answer that the common UStar file format -- most common tar archive format -- does split the device number into major and minor. (They are typically encoded as seven octal digits each, so for compatibility reasons one should limit to 21-bit unsigned major and 21-bit unsigned minor. This also means that mapping the device number to just the major or just the minor is not a reliable approach.)
The following include file expanding on Jonathon Reinhart's answer, after digging on the web for the various systems man pages and documentation (for makedev(), major(), and minor()), plus comments to this question.
#if defined(custom_makedev) && defined(custom_major) && defined(custom_minor)
/* Already defined */
#else
#undef custom_makedev
#undef custom_major
#undef custom_minor
#if defined(__linux__) || defined(__GLIBC__)
/* Linux, Android, and other systems using GNU C library */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(_WIN32)
/* 32- and 64-bit Windows. VERIFY: These are just a guess! */
#define custom_makedev(dmajor, dminor) ((((unsigned int)dmajor << 8) & 0xFF00U) | ((unsigned int)dminor & 0xFFFF00FFU))
#define custom_major(devnum) (((unsigned int)devnum & 0xFF00U) >> 8)
#define custom_minor(devnum) ((unsigned int)devnum & 0xFFFF00FFU)
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
/* FreeBSD, OpenBSD, NetBSD, and DragonFlyBSD */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(__APPLE__) && defined(__MACH__)
/* Mac OS X */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(_AIX) || defined (__osf__)
/* AIX, OSF/1, Tru64 Unix */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(hpux)
/* HP-UX */
#include <sys/sysmacros.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(sun)
/* Solaris */
#include <sys/types.h>
#include <sys/mkdev.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#else
/* Unknown OS. Try a the BSD approach. */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#if defined(makedev) && defined(major) && defined(minor)
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#endif
#endif
#if !defined(custom_makedev) || !defined(custom_major) || !defined(custom_minor)
#error Unknown OS: please add definitions for custom_makedev(), custom_major(), and custom_minor(), for device number major/minor handling.
#endif
#endif
One could glean additional definitions from existing UStar-format -capable archivers. Compatibility with existing implementations on each OS/architecture is, in my opinion, the most important thing here.
The above should cover all systems using GNU C library, Linux (including Android), FreeBSD, OpenBSD, NetBSD, DragonFlyBSD, Mac OS X, AIX, Tru64, HP-UX, and Solaris, plus any that define the macros when <sys/types.h> is included. Of the Windows part, I'm not sure.
As I understand it, Windows uses device 0 for all normal files, and a HANDLE (a void pointer type) for devices. I am not at all sure whether the above logic is sane on Windows, but many older systems put the 8 least significant bits of the device number into minor, and the next 8 bits into major, and the convention seems to be that any leftover bits would be put (without shifting) into minor, too. Examining existing UStar-format tar archives with references to devices would be useful, but I personally do not use Windows at all.
If a system is not detected, and the system does not use the BSD-style inclusion for defining the macros, the above will error out stopping the compilation. (I would personally add compile-time machinery that could help finding the correct header definitions, using e.g. find, xargs, and grep, in case that happens, with a suggestion to send the addition upstream, too. touch empty.h ; cpp -dM empty.h ; rm -f empty.h should show all predefined macros, to help with identifying the OS and/or C library.)
Originally, POSIX stated that dev_t must be an arithmetic type (thus, theoretically, it might have been some variant of float or double on some systems), but IEEE Std 1003.1, 2013 Edition says it must be an integer type. I would wager that means no known POSIX-y system ever used a floating-point dev_t type. It would seem that Windows uses a void pointer, or HANDLE type, but Windows is not POSIX-compliant anyway.
Use the major() and minor() macros after defining BSD_SOURCE.
The makedev(), major(), and minor() functions are not specified in
POSIX.1, but are present on many other systems.
http://man7.org/linux/man-pages/man3/major.3.html
I have a program based on an antique version of ls for Minix, but much mangled modified by me since then. It has the following code to detect the major and minor macros — and some comments about (now) antique systems where it has worked in the past. It assumes a sufficiently recent version of GCC is available to support #pragma GCC diagnostic ignored etc. You have to be trying pretty hard (e.g. clang -Weverything) to get the -Wunused-macros option in effect unless you include it explicitly.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
/* Defines to ensure major and minor macros are available */
#define _DARWIN_C_SOURCE /* In <sys/types.h> on MacOS X */
#define _BSD_SOURCE /* In <sys/sysmacros.h> via <sys/types.h> on Linux (Ubuntu 12.0.4) */
#define __EXTENSIONS__ /* Maybe beneficial on Solaris */
#pragma GCC diagnostic pop
/* From Solaris 2.6 sys/sysmacros.h
**
** WARNING: The device number macros defined here should not be used by
** device drivers or user software. [...] Application software should make
** use of the library routines available in makedev(3). [...] Macro
** routines bmajor(), major(), minor(), emajor(), eminor(), and makedev()
** will be removed or their definitions changed at the next major release
** following SVR4.
**
** #define O_BITSMAJOR 7 -- # of SVR3 major device bits
** #define O_BITSMINOR 8 -- # of SVR3 minor device bits
** #define O_MAXMAJ 0x7f -- SVR3 max major value
** #define O_MAXMIN 0xff -- SVR3 max major value
**
** #define L_BITSMAJOR 14 -- # of SVR4 major device bits
** #define L_BITSMINOR 18 -- # of SVR4 minor device bits
** #define L_MAXMAJ 0x3fff -- SVR4 max major value
** #define L_MAXMIN 0x3ffff -- MAX minor for 3b2 software drivers.
** -- For 3b2 hardware devices the minor is restricted to 256 (0-255)
*/
/* AC_HEADER_MAJOR:
** - defines MAJOR_IN_MKDEV if found in sys/mkdev.h
** - defines MAJOR_IN_SYSMACROS if found in sys/macros.h
** - otherwise, hope they are in sys/types.h
*/
#if defined MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif defined MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#elif defined(MAJOR_MINOR_MACROS_IN_SYS_TYPES_H)
/* MacOS X 10.2 - for example */
/* MacOS X 10.5 requires -D_DARWIN_C_SOURCE or -U_POSIX_C_SOURCE - see above */
#elif defined(USE_CLASSIC_MAJOR_MINOR_MACROS)
#define major(x) ((x>>8) & 0x7F)
#define minor(x) (x & 0xFF)
#else
/* Hope the macros are in <sys/types.h> or otherwise magically visible */
#endif
#define MAJOR(x) ((long)major(x))
#define MINOR(x) ((long)minor(x))
You will justifiably not be all that keen on the 'hope the macros are … magically visible' part of the code.
The reference to AC_HEADER_MAJOR is to the macro in the autoconf that deduces this information. It would be relevant if you have a config.h file generated by autoconf.
POSIX
Note that the POSIX pax command defines the ustar format and specifies that it includes devmajor and devminor in the information, but adds:
… Represent character special files and block special files respectively. In this case the devmajor and devminor fields shall contain information defining the device, the format of which is unspecified by this volume of POSIX.1-2008. Implementations may map the device specifications to their own local specification or may ignore the entry.
This means that there isn't a fully portable way to represent the numbers. This is not wholly unreasonable (but it is a nuisance); the meanings of the major and minor device numbers varies across platforms and is unspecified too. Any attempt to create block or character devices via ustar format will only work reasonably reliably if the source and target machines are running the same (version of the same) operating system — though usually they're portable across versions of the same operating system.
Is it possible to create a preprocessor function that will cause multiple other preoprocessor macros to be defined?
I'm working in a micro controller framework that requires a few macros to be made in order for a generic interrupt handler to function:
<MODULE_NAME>_IRQ_PIN //ex: PORTB_PIN(0)
<MODULE_NAME>_IRQ_IN_REGISTER //ex: GPIO_PBIN
<MODULE_NAME>_IRQ_NUMBER //ex: GPIO_IRQA
<MODULE_NAME>_IRQ_INTCFG_REG //ex: GPIO_INTCFGA
I am trying to make this process more generic and easier from an implementation standpoint. There are about ten of these macros that need to be defined, but their definitions can all be derived when given 1) the port name 2) the pin number and 3) the IRQ name. I am hoping then to create a pre-processor function that will result in the generation of all of these macros. Something like:
#define MAKE_INTERRUPT_MACROS(module, port, pin, irq_num) \
#define module##_IRQ_pin PORT##port##_PIN(##pin##) \
#define module##_IRQ_IN_REGISTER GPIO_P##port##IN \
#define module##_IRQ_NUMBER GPIO_IRQ##irq_num \
#define module##_IRQ_INTCFG_REG GPIO_INTCFG##irq_num
Is there a legal way to get the proprocessor to do something like the above, where a single preprocessor function causes the generation of multiple other macros based on the parameters passed to the function?
I think this classical scheme may solve your problem. This is a simple and clear way:
#ifdef CPU_X
#define IRQ_PIN 0
#define IRQ_IN_REGISTER 3
#define IRQ_NUMBER 11
#define IRQ_INTCFG_REG 12
#endif
#ifdef CPU_YY
#define IRQ_PIN PORTB_PIN(1)
#define IRQ_IN_REGISTER GPIO_PBIN(6)
#define IRQ_NUMBER GPIO_IRQA(9)
#define IRQ_INTCFG_REG GPIO_INTCFGA(0xA)
#endif
#ifdef CPU_KK
/* .
. Another CPU
.
*/
#endif
#ifdef CPU_K2
/* .
. Another CPU
.
*/
#endif
You may compile the code specifying the CPU using -D CPU_xx and the problem shoudl be solved!
I assume you might have some other macros (E.G.: GPIO_IRQA(9)), and in CPU_YY I've used it, but It might be used also for the other CPUs.
If you can use C++ rather than C, look at using classes, one per CPU type, and simply use constants and interfaces in the class. Then, you don't even care that they are different, simply use the same names to access them (the differentiation is done based upon the class being instantiated.
If you really and truly must use C (such as writing a device driver), you can use the approach device driver writers use (all flavors of *nix, VxWorks, PSOS, QNX, and most of the old DEC OSs use this approach, don't know about Windows): Simply build a structure containing the values and any functions you may need to manipulate the hardware (or anything else, for that matter). Create one instance of this structure per hardware (or in your case, module) type. Then indirect through the structure.
Example:
struct module_wrapper {
const char *module_name;
int irq_pin;
int irq_register;
int irq_number;
int irq_intcfg_reg;
int (*init_fcn)(void);
int (*reg_access)(int register_number);
int (*open)(void);
int (*close)(void);
int (*read)(char *dst_buffer, int len);
int (*write)(const char *src_buffer, int len);
};
module_wrapper portB = { /* initialize here */ };
module_wrapper gpio = { /* initialize here */ };
printf("GPIO pin %d\n", gpio.irq_pin);
Obviously, modify as desired. You can also replace the constant variables with functions that return the values.
You can't define other macros with a macro, but you achieve something similar by doing it kind of in a totally opposite way.
You could autogenerate a file which has the following block for each possible module:
#ifdef <MODULE>_IRQ_DATA
#define <MODULE>_IRQ_pin CALL(GET_IRQ_PIN, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_IN_REGISTER CALL(GET_IRQ_IN_REGISTER, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_NUMBER CALL(GET_IRQ_NUMBER, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_INTCFG_REG CALL(GET_IRQ_INTCFG_REG, <MODULE>_IRQ_DATA)
#endif
And then have:
#define CALL(MACRO, ...) MACRO(__VA_ARGS__)
#define GET_IRQ_PIN(port, pin, irq_num) PORT##port##_PIN(pin)
#define GET_IRQ_IN_REGISTER(port, pin, irq_num) GPIO_P##port##IN
#define GET_IRQ_NUMBER(port, pin, irq_num) GPIO_IRQ##irq_num
#define GET_IRQ_INTCFG_REG(port, pin, irq_num) GPIO_INTCFG##irq_num
(Depending on how the defines are used, you can possibly get rid of the #ifdef-#endif -pairs, eg. if all of them must/can always be defined)
Then actually defining the needed values could be done with just:
#define <MODULE>_IRQ_DATA B,0,A