473,325 Members | 2,792 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,325 software developers and data experts.

Help with function-like macros

On a project I'm working on, I ran across the following macros:

/* assume s is struct stream *, s->p is char, v is unit16_t or uint32_t */
#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
#define in_uint32_le(s,v) { in_uint16_le(s,v) \
v += *((s)->p++) << 16; v += *((s)->p++) << 24; }

I'm personally not fond of function-like macros and wanted to turn these
into static inline functions, but I'm having trouble doing so because the
above macros modify their second argument -- one of the reasons I dislike
them in the first place. This seems to require that the signatures be
changed to:

static inline uint16_t in_uint16_le(struct stream *s);
static inline uint32_t in_uint32_le(struct stream *s);

However, I'm not comfortable both swapping out the macros _and_ rewriting
hundreds of calls to each at the same time, so I'd like some function-like
macros with the new signature as a transition step. I'm also concerned that
there may be compilers out there that puke on "static inline" or don't
optimize it properly, so I'd only use them on platforms where it works
equally well or better.

However, I can't figure out exactly how to write the new macros; can someone
please send reworked versions?

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

Nov 14 '05 #1
3 2633


Stephen Sprunk wrote:
On a project I'm working on, I ran across the following macros:

/* assume s is struct stream *, s->p is char, v is unit16_t or uint32_t */
#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
#define in_uint32_le(s,v) { in_uint16_le(s,v) \
v += *((s)->p++) << 16; v += *((s)->p++) << 24; }
I would rather use the do....while (0) form (two threads above this
one).
s->p seems to be of type char * instead of char, as indicated above.
If this is true: Consider the use of unsigned char if you can.
I'm personally not fond of function-like macros and wanted to turn these
into static inline functions, but I'm having trouble doing so because the
above macros modify their second argument -- one of the reasons I dislike
them in the first place. This seems to require that the signatures be
changed to:

static inline uint16_t in_uint16_le(struct stream *s);
static inline uint32_t in_uint32_le(struct stream *s);
Why not stay with the "interface" given by the macro?

static inline void in_uint16_le(struct stream *s, uint16_t *v);
static inline void in_uint32_le(struct stream *s, uint32_t *v);

Replacing in_uintN_t(s,v) by in_uintN_t(s,&(v)) is easier.

Notes: You did not comment on the change of the value of p,
so I guess that this is intended.
Note also that uint16_t is not guaranteed by the C99 standard
whereas uint_least16_t and uint_fast16_t are (same for 8, 32, 64 and
other numbers of bits).

However, I'm not comfortable both swapping out the macros _and_ rewriting
hundreds of calls to each at the same time, so I'd like some function-like
macros with the new signature as a transition step. I'm also concerned that
there may be compilers out there that puke on "static inline" or don't
optimize it properly, so I'd only use them on platforms where it works
equally well or better.

However, I can't figure out exactly how to write the new macros; can someone
please send reworked versions?


The ugly thing is that you have to work with the comma operator.
Consider

#include <stdio.h>

#define get16(p) ((p)+=2, *((p)-2)+(*((p)-1)<<8))

int main (void)
{
unsigned char *ptr, arr[]={255,255};

ptr = arr;

printf("%u\n",get16(ptr));

return 0;
}
Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.

Nov 14 '05 #2


Michael Mair wrote:


Stephen Sprunk wrote:
On a project I'm working on, I ran across the following macros:

/* assume s is struct stream *, s->p is char, v is unit16_t or
uint32_t */
#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
#define in_uint32_le(s,v) { in_uint16_le(s,v) \
v += *((s)->p++) << 16; v += *((s)->p++) << 24; }

I would rather use the do....while (0) form (two threads above this
one).
s->p seems to be of type char * instead of char, as indicated above.
If this is true: Consider the use of unsigned char if you can.
I'm personally not fond of function-like macros and wanted to turn these
into static inline functions, but I'm having trouble doing so because the
above macros modify their second argument -- one of the reasons I dislike
them in the first place. This seems to require that the signatures be
changed to:

static inline uint16_t in_uint16_le(struct stream *s);
static inline uint32_t in_uint32_le(struct stream *s);

Why not stay with the "interface" given by the macro?

static inline void in_uint16_le(struct stream *s, uint16_t *v);
static inline void in_uint32_le(struct stream *s, uint32_t *v);

Replacing in_uintN_t(s,v) by in_uintN_t(s,&(v)) is easier.

Notes: You did not comment on the change of the value of p,
so I guess that this is intended.
Note also that uint16_t is not guaranteed by the C99 standard
whereas uint_least16_t and uint_fast16_t are (same for 8, 32, 64 and
other numbers of bits).

However, I'm not comfortable both swapping out the macros _and_ rewriting
hundreds of calls to each at the same time, so I'd like some
function-like
macros with the new signature as a transition step. I'm also
concerned that
there may be compilers out there that puke on "static inline" or don't
optimize it properly, so I'd only use them on platforms where it works
equally well or better.

However, I can't figure out exactly how to write the new macros; can
someone
please send reworked versions?

The ugly thing is that you have to work with the comma operator.
Consider

#include <stdio.h>

#define get16(p) ((p)+=2, *((p)-2)+(*((p)-1)<<8))


Just thought about it; for the record:
"& 0xFF" makes sense for CHAR_BIT > 8, so for portable code, you may
want to do it like this:

#define get8n(p) (*(p) & 0xFF)
#define get16(p) ((p)+=2, get8n((p)-2) + get8n((p)-1)<<8)

(untested, "n" stands for non-modifying)

int main (void)
{
unsigned char *ptr, arr[]={255,255};

ptr = arr;

printf("%u\n",get16(ptr));

return 0;
}
Cheers
Michael

--
E-Mail: Mine is a gmx dot de address.

Nov 14 '05 #3
"Stephen Sprunk" <st*****@sprunk.org> writes:
On a project I'm working on, I ran across the following macros:

/* assume s is struct stream *, s->p is char, v is unit16_t or uint32_t */

#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
#define in_uint32_le(s,v) { in_uint16_le(s,v) \
v += *((s)->p++) << 16; v += *((s)->p++) << 24; }
First suggestion: these macros can be written in expression form
rather than statement form, and it's probably a good idea to do
that:

#define in_uint16_le(s,v) (v = *((s)->p++), v += *((s)->p++) << 8)
/* etc */

I mention this because this transformation should aid in converting
to a more function-call-like semantics.

I'm personally not fond of function-like macros and wanted to turn these
into static inline functions, but I'm having trouble doing so because the
above macros modify their second argument -- one of the reasons I dislike
them in the first place. This seems to require that the signatures be
changed to:

static inline uint16_t in_uint16_le(struct stream *s);
static inline uint32_t in_uint32_le(struct stream *s);

However, I'm not comfortable both swapping out the macros _and_ rewriting
hundreds of calls to each at the same time, so I'd like some function-like
macros with the new signature as a transition step. I'm also concerned that
there may be compilers out there that puke on "static inline" or don't
optimize it properly, so I'd only use them on platforms where it works
equally well or better.

However, I can't figure out exactly how to write the new macros; can someone
please send reworked versions?


Here is a sketch of an approach. First step:

#define in_uint16_le(s,v) in_puint16_le(s,&(v))
#define in_uint32_le(s,v) in_puint32_le(s,&(v))

#define in_puint16_le(s,v) (*(v) = *((s)->p++), *(v) += *((s)->p++) << 8 )
#define in_puint32_le(s,v) \
(*(v) = *((s)->p++), *(v) += *((s)->p++) << 8, \
*(v) += *((s)->p++) << 16, *(v) += *((s)->p++) << 24)

The first step transitions to macros that use an address, but without
needing to change any of the macro calls (not counting the changes
needed after switching to the expression form, which should be only
adding ;'s in places).
Second step - allow functions in place of macros:

#define in_uint16_le(s,v) in_puint16_le(s,&(v))
#define in_uint32_le(s,v) in_puint32_le(s,&(v))

#if EXPAND_in_puint_X_le_AS_CALLS
# define in_puint16_le(s,v) C_in_puint16_le(s,v)
# define in_puint32_le(s,v) C_in_puint32_le(s,v)
#else
# define in_puint16_le(s,v) CPP_in_puint16_le(s,v)
# define in_puint32_le(s,v) CPP_in_puint32_le(s,v)
#endif

#define CPP_in_puint16_le(s,v) \
(*(v) = *((s)->p++), *(v) += *((s)->p++) << 8 )
#define CPP_in_puint32_le(s,v) \
(*(v) = *((s)->p++), *(v) += *((s)->p++) << 8, \
*(v) += *((s)->p++) << 16, *(v) += *((s)->p++) << 24)

static uint16 inline
C_in_puint16_le( struct stream *s, uint16 *v ){
return CPP_in_puint16_le( s, v );
}

static uint32 inline
C_in_puint32_le( struct stream *s, uint32 *v ){
return CPP_in_puint32_le( s, v );
}

By #define'ing EXPAND_in_puint_X_le_AS_CALLS as 0 or 1,
either CPP expansion behavior or function call behavior
can be generated.

Note 1: to get void results rather than uint16/uint32 results, put
casts in the bottom-most macros, and change the function definitions
appropriately.

Note 2: factoring - it would be nice if the body of the 16 bit macro
didn't have to be replicated. I didn't see any easy way of doing
that, given the type requirements.

Note 3: argument types - if the function call version is used, the
type of the argument v must match the parameter. I count this as a
plus rather than a minus. The CPP expansion version can be used as a
fallback for first compile, comparison debugging, etc.

Note 4: on platforms that don't provide static inline functions, use
CPP directives to exclude the static inline function definitions and
to insure that EXPAND_in_puint_X_le_AS_CALLS will be 0. (That code
was left out above so as not to clutter the example.)
Step 3: if desired, calls such as

in_uint16_le( s, v );

can be changed to

in_puint16_le( s, &v );

where ever they appear. Similarly calls to in_uint32_le.
Disclaimer: I have test compiled code along the lines
of the above, but have not copied/pasted the exact code,
so there may be minor typographical erros.
Nov 14 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Dale McGorman | last post by:
The following is some code that I am trying to bring over from VB 6.0, that I have working there. I am trying to get to where I can talk to a USB device. I am stuck on how to correctly pass params...
4
by: Jim Hubbard | last post by:
I have some C# code that is supposed to wrap the defrag APIs and I am trying to convert it to VB.Net (2003). But, I keep having problems. The C# code is relatively short, so I'll post it...
5
by: xuatla | last post by:
Hi, I encountered the following compile error of c++ and hope to get your help. test2.cpp: In member function `CTest CTest::operator+=(CTest&)': test2.cpp:79: error: no match for 'operator='...
7
by: Alan Bashy | last post by:
Please, guys, In need help with this. It is due in the next week. Please, help me to implement the functions in this programm especially the first three constructor. I need them guys. Please, help...
7
by: x muzuo | last post by:
Hi guys, I have got a prob of javascript form validation which just doesnt work with my ASP code. Can any one help me out please. Here is the code: {////<<head> <title>IIBO Submit Page</title>...
5
by: Craig Keightley | last post by:
Please help, i have attached my page which worksin IE but i cannnot get the drop down menu to fucntion in firefox. Any one have any ideas why? Many Thanks Craig ...
4
by: dixie | last post by:
Help, I'm really out of my depth here (not unusual I hear you say :-). I have just installed HTML Help in an application. I told it in the Project Properties the path to the help file. I then...
8
by: Don | last post by:
I have a third party C++ DLL that I am trying to use from C#. The specific function I am trying to use is declared in C++ as follows: ladybugConvertToMultipleBGRU32( LadybugContext ...
5
by: althafexcel | last post by:
hi everyone Im trying to include an external js in my aspx page under the head tag, it doesn't load or it displays an object expected error whenver the function from the .js is called. Actually...
22
by: Amali | last post by:
I'm newdie in c programming. this is my first project in programming. I have to write a program for a airline reservation. this is what i have done yet. but when it runs it shows the number of...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.