473,406 Members | 2,259 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,406 software developers and data experts.

undefined behavior in "macro-based" single-linked list impl...

I was wondering if the 'SLINK_*' and 'SLIST_*' macros, which
implement a simple singly-linked list, will produce _any_ possible
undefined behavior:
____________________________

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

/* Single-Link API
____________________________________*/
typedef struct slink_s slink;

struct slink_s {
slink* next;
};

#define SLINK_STATICINIT() {0}

#define SLINK_GET_NEXT(mp_this) ( \
(mp_this)->next \
)

#define SLINK_SET_NEXT(mp_this, mp_link) ( \
(mp_this)->next = (mp_link) \
)

/* Single-List API
____________________________________*/
typedef struct slist_s slist;

struct slist_s {
slink front;
};

/* static init */
#define SLIST_STATICINIT() { \
SLINK_STATICINIT() \
}

/* returns the front of the list */
#define SLIST_GET_FRONT(mp_this) ( \
SLINK_GET_NEXT(&(mp_this)->front) \
)

/* returns the mp_link parameter */
#define SLIST_PUSH_FRONT(mp_this, mp_link) ( \
SLINK_SET_NEXT(mp_link, SLIST_GET_FRONT(mp_this)), \
SLINK_SET_NEXT(&(mp_this)->front, mp_link) \
)

/* returns 0 on failure */
#define SLIST_POP_FRONT(mp_this, mp_plink) ( \
*(mp_plink) = SLIST_GET_FRONT(mp_this), \
*(mp_plink) \
? SLINK_SET_NEXT(&(mp_this)->front, \
SLINK_GET_NEXT(*(mp_plink))), 1 \
: 0 \
)

/* Test Application
____________________________________*/
#define TEST_DEPTH() 5

static int exit_prompt(int const, char const* const);
static slist g_list = SLIST_STATICINIT();
int main(void) {
int t;
for(t = 0; t < TEST_DEPTH(); ++t) {
int i;
slink* _this;
#define LIST_DEPTH() (t + 5)

for(i = 0; i < LIST_DEPTH(); ++i) {
slink* cmp = 0;
_this = malloc(sizeof(*_this));
cmp = SLIST_PUSH_FRONT(&g_list, _this);
printf("(%p/%p/%p)-SLIST_PUSH_FRONT(...)\n",
(void*)_this,
(void*)SLIST_GET_FRONT(&g_list),
(void*)SLINK_GET_NEXT(_this));
assert(_this == cmp);
}
printf("(%i)-FILLED! Press <ENTERTo Continue...\n", t);
getchar();
_this = SLIST_GET_FRONT(&g_list);
while(_this) {
printf("(%p)-SLIST_GET_FRONT(...)\n", (void*)_this);
_this = SLINK_GET_NEXT(_this);
}
printf("(%i)-ITERATED! Press <ENTERTo Continue...\n", t);
getchar();
while(SLIST_POP_FRONT(&g_list, &_this)) {
printf("(%p)-SLIST_POP_FRONT(...)\n", (void*)_this);
free(_this);
}
printf("(%i)-FLUSHED! Press <ENTERTo Continue...\n", t);
getchar();

puts("\n----------------------------------");
}

assert(! SLIST_GET_FRONT(&g_list));

return exit_prompt(
0, "\n\n\n\
_______________________\npress <ENTERto exit...\n");
}
int exit_prompt(int const status, char const* const buf) {
printf("%s", buf);
getchar();
return status;
}

____________________________

Thank you in advance.
Sep 27 '07 #1
2 2141
"Chris Thomasson" <cr*****@comcast.netwrote in message
news:9K******************************@comcast.com. ..
>I was wondering if the 'SLINK_*' and 'SLIST_*' macros, which implement a
simple singly-linked list, will produce _any_ possible undefined behavior:
Sorry for any copy-and-paste errors; here is a link to the code in question:
____________________________
http://appcore.home.comcast.net/misc/macro-slist-c.html
____________________________

:^0

Sep 27 '07 #2
Chris Thomasson wrote On 09/27/07 05:59,:
"Chris Thomasson" <cr*****@comcast.netwrote in message
news:9K******************************@comcast.com. ..
>>I was wondering if the 'SLINK_*' and 'SLIST_*' macros, which implement a
simple singly-linked list, will produce _any_ possible undefined behavior:


Sorry for any copy-and-paste errors; here is a link to the code in question:

>>____________________________


http://appcore.home.comcast.net/misc/macro-slist-c.html
The macros look all right to me. SLIST_POP_FRONT
could be streamlined a bit, but I think it's correct.
They're not safe if the arguments have side-effects:

SLIST_PUSH_FRONT(list, getAnotherNode());
or
slist half[2] = { SLIST_STATICINIT(), SLIST_STATICINIT() };
int which = 1;
/* Divide the input nodes among the two lists: */
while ((node = getAnotherNode()) != NULL)
SLIST_PUSH_FRONT(half[ which ^= 1 ], node);

It's a shame that SLIST_POP_FRONT needs an auxiliary
output variable. I can sympathize with the desire to move
the success/failure indication "out of band," but in this
case it seems clumsy. NULL is a widely-understood "failure"
value for many pointer-related things, and would not be a
stylistic shock to anyone. SLIST_POP_FRONT already uses
the nullness of the link to detect end-of-list; why not
let the user do the same?

It's too bad that SLINK_SET_NEXT and SLINK_GET_NEXT
differ by only one letter, buried in the middle of the
names. Fortunately, their argument counts are different,
so the compiler will holler if/when somebody mixes them up.

It'd be Really Ugly to use these macros with nodes
that can inhabit multiple lists simultaneously. Sparse
matrices, for example, where each node might be linked
in both a row list and a column list:

struct cell {
int row, col;
double value;
slink nextinrow;
slink nextincol;
};

Navigating such a setup will find you using offsetof()
and casts more heavily than is healthy. (True, the matrix
as a whole is not a "simple singly-linked list." But its
rows and columns are when viewed separately, and it's a
shame that the macros make them hard to manipulate.)

If I were going to do something like this, I think
I'd use functions instead of macros: all the side-effect
safety issues disappear, it's easy to add sanity-checking
in debug builds, and so on. Also, you gain some type
safety: SLINK_GET_NEXT will work quite happily with any
pointer to a struct or union with a `next' member, even
if that pointer is not an `slink*'. Compilers are pretty
good at expanding simple functions in-line, especially if
given C99's `inline' hint.

--
Er*********@sun.com
Sep 27 '07 #3

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

Similar topics

188
by: infobahn | last post by:
printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */
40
by: Dave Hansen | last post by:
Please note crosspost. Often when writing code requiring function pointers, it is necessary to write functions that ignore their formal parameters. For example, a state machine function might...
3
by: xudeutsch | last post by:
I have such a block in C++ #pragma pack(push,4) #define STATE_NULL 0x0000 #pragma pack(pop) and I need to convert it to C#. I want to use the "MarshalAs" attribute, but i dont know which...
47
by: sudharsan | last post by:
Hi could you please explain wat atoi( ) function is for and an example how to use it?
21
by: Marius Lazer | last post by:
Is it possible to write a macro that single-quotes its argument? #define SOME_MACRO(x) such that SOME_MACRO(foo) expands to 'foo' Thanks, Marius
15
by: rover8898 | last post by:
Hello all, I used setjmp() in a recent of program of mine (it is not completed, so I have not the chance to test it out yet). I am not very profocient in C coding as are some of my co-workers....
0
Boxcar74
by: Boxcar74 | last post by:
Hi Everybody!!! I have an Issue. I have an Excel file that queries an Access db. I’m trying to have it so I don’t have to keep updating it manually everyday and save it to a network drive...
9
by: anon.asdf | last post by:
In terms of efficieny: Is it better to use multiple putchar()'s after one another as one gets to new char's OR is it better to collect the characters to a char-array first, and then use...
4
by: Gestorm | last post by:
Hi all, I found a macro "USE_VAR" in the code of bash-3.2 as follows: /*file: bash-3.2/shell.c*/ 344 USE_VAR(argc); 345 USE_VAR(argv); 346 USE_VAR(env); 347 USE_VAR(code); 348 ...
3
by: Kappucino XL | last post by:
Hi There.. What is the Macro or Code Builder Event, For Copying And Pasting. i.e: I need to click on a field in a textbox, and it must be copied jus by clicking on it. Then I want to click on...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

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.