Features of Using Macros C

Reading the C library socket interface code, I found this:

/* Types of sockets. */ enum __socket_type { SOCK_STREAM = 1, /* Sequenced, reliable, connection-based byte streams. */ #define SOCK_STREAM SOCK_STREAM SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams of fixed maximum length. */ #define SOCK_DGRAM SOCK_DGRAM ... 

This "idiom" is used in all bits of /socket.h. I'm just wondering what is the purpose of these macros?

+6
source share
3 answers

These constants were usually #define s, so what you see is probably there to protect you from accidentally mixing old and new header files. The advantage of using enum to define constants is that enum members tend to be available in the debugger, and #define macros do not.

If you (accidentally) include some other header file that #define SOCK_STREAM also tries, you will get a compiler warning instead of silently using a possibly incorrect value.

UPDATE

Looking through the glibc git repo , I found the specific commit that #define s added, with this comment:

 * sysdeps/generic/socketbits.h: Also make SOCK_* constants available as macros so that #ifdef works. * sysdeps/unix/sysv/linux/socketbits.h: Likewise. 

There you have it.

+6
source

This is the C-equivalent of an "enumeration."

The logical socket type "stream" (SOCK_STREAM) corresponds to the binary value "1". A "datagram" (SOCK_DGRAM) is a type of "2". Etc.

Sockets were invented before enum became part of C.

The above idiom allows you to use "SOCK_STREAM" (for example) in your code; it also allows the use of "#ifndef SOCK_STREAM" (which may be significant in some kind of legacy program).

+2
source

Historical systems used macros and did not have such enumerations.

Older versions of POSIX / Single Unix (such as SUSv3 ) require that SOCK_xxx be macros. This means that these constants can be used in preprocessor directives (for example, #ifdef SOCK_DGRAM ). Sometimes it can be useful to check during assembly whether the system supports a non-standard socket type.

Newer standards (for example, SUSv4 ) have softened this requirement in the system: the constants SOCK_xxx can be any symbolic constants . This includes preprocessor macros, as well as any other definition that creates a constant expression (suitable for static initializers and other contexts requiring a constant expression), such as enumeration constants.

The execution that you are looking for conformance to SUSv3 (and SUSv4, SUSv3, implies conformity to SUSv4 in this regard). An implementation that defined only the enumeration, not the constants, would be compatible with SUSv4, but not with SUSv3.

The advantage of defining an enumeration is that it allows the compiler to give decent feedback if the SOCK_xxx constant SOCK_xxx used in a context that does not call it, or if an arbitrary integer is used where the SOCK_xxx value SOCK_xxx expected.

The same applies to many similar sets of constants.

+1
source

Source: https://habr.com/ru/post/920003/


All Articles