major and minor macros defined in sys/sysmacros.h

2020-06-08 02:14发布

I'm writing a class that has a matrix-like structure and I want to have a member function named minor to be the same as the matrix operation. This triggers some errors. A minimal test case on my system:

#include <iterator>
void minor(int row, int col);

When compiled, clang provides the following error:

$ clang++ -Weverything -std=c++11 test.cpp 
test.cpp:2:21: error: too many arguments provided to function-like macro invocation
void minor(int row, int col);
                    ^
/usr/include/x86_64-linux-gnu/sys/sysmacros.h:67:10: note: macro 'minor' defined here
# define minor(dev) gnu_dev_minor (dev)
         ^
test.cpp:2:6: error: variable has incomplete type 'void'
void minor(int row, int col);
     ^
2 errors generated.
$

The relevant portion of sys/sysmacros.h is:

/* Access the functions with their traditional names.  */
# define major(dev) gnu_dev_major (dev)
# define minor(dev) gnu_dev_minor (dev)
# define makedev(maj, min) gnu_dev_makedev (maj, min)

Clearly, these specific macros could be #undef'd, but it seems quite silly that such routine words as major and minor would be defined as macros, particularly when pulling in part of the C++ standard library. Is there some reason these need to be defined? Is this a bug in the standard library I'm using? (libstdc++ 4.8.2 as in Debian testing)

1条回答
成全新的幸福
2楼-- · 2020-06-08 03:00

According to the C++ standard those names shouldn't be reserved to the implementation and thus be available.

According to man 3 makedev:

The makedev(), major(), and minor() functions are not specified in POSIX.1, but are present on many other systems

and

These interfaces are defined as macros. Since glibc 2.3.3, they have been aliases for three GNU-specific functions: gnu_dev_makedev(), gnu_dev_major(), and gnu_dev_minor(). The latter names are exported, but the traditional names are more portable.

It seems that they aren't removed for backward compatibility (e.g. https://bugzilla.redhat.com/show_bug.cgi?id=130601).

I think you could #undef them without major issues (many projects proceed in this way).

With G++/CLANG/MSVC you could also do something like:

#pragma push_macro("minor")
#undef minor

// do what you need

#pragma pop_macro("minor")

It's ugly, but helps with naming conflicts.

Moreover, depending on how your code is structured, this trick can be useful:

#define minor(dev) gnu_dev_major(dev)

void (minor)(int row, int col) { /* ... */ }

In the function definition line, the character after 'minor' is a close parenthesis, so it is not a macro invocation.

查看更多
登录 后发表回答