Solved

C qsort compare function issue

Posted on 2017-03-16
6
11 Views
Last Modified: 2017-03-16
I'm attempting to sort what would normally be a multi-dimensional array (CIDR block in 0, CIDR mask in 1) as a single-dimensional array of structures.  Using qsort, telling it the data size is the size of the structure, and a hopefully-clever compare function to compare only the CIDR blocks using structure offsets.

The compilation fails in the compare function with the error:

sorttest.c: In function 'ib_cmpfunc':
sorttest.c:22:27: error: request for member 'ib_blackaddr' in something not a structure or union
   if ((*(ib_arrayelement)a.ib_blackaddr - *(ib_arrayelement)b.ib_blackaddr) > 0) return 1;
                           ^
sorttest.c:22:62: error: request for member 'ib_blackaddr' in something not a structure or union
   if ((*(ib_arrayelement)a.ib_blackaddr - *(ib_arrayelement)b.ib_blackaddr) > 0) return 1;
                                                              ^
sorttest.c:23:27: error: request for member 'ib_blackaddr' in something not a structure or union
   if ((*(ib_arrayelement)a.ib_blackaddr - *(ib_arrayelement)b.ib_blackaddr) < 0) return -1;
                           ^
sorttest.c:23:62: error: request for member 'ib_blackaddr' in something not a structure or union
   if ((*(ib_arrayelement)a.ib_blackaddr - *(ib_arrayelement)b.ib_blackaddr) < 0) return -1;

Open in new window


Here's the code used to generate the test program.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#define BLACKLIST_SIZE 512

typedef struct {
    /* IPV4 address as 32-bit integer */
  unsigned long ib_blackaddr;
    /* CIDR mask as 32-bit integer */
  unsigned long ib_blackmask;
}  ib_arrayelement;

  /* Number of entries in the blacklist table */
int ib_blacklist_size;

  /* IPv4 address - CIDR mask blacklist */
ib_arrayelement ib_blackarray[BLACKLIST_SIZE];

static int ib_cmpfunc (const void *a, const void *b) {
  if ((*(ib_arrayelement)a.ib_blackaddr - *(ib_arrayelement)b.ib_blackaddr) > 0) return 1;
  if ((*(ib_arrayelement)a.ib_blackaddr - *(ib_arrayelement)b.ib_blackaddr) < 0) return -1;
  return 0;
}

void main (int argc, char **argv) {

  qsort(ib_blackarray, ib_blacklist_size,
        sizeof(ib_arrayelement), ib_cmpfunc);

  return;
}

Open in new window


The qsort compare function is too deep in pointers for me to follow what the problem is; I don't normally do anything this obscure.  Can someone point me at a solution?

Side note:  This is c on a Debian linux host.  Not C++, nor Windows.
0
Comment
Question by:Dr. Klahn
  • 3
  • 3
6 Comments
 
LVL 32

Expert Comment

by:phoffric
http://ideone.com/iizCtE
See if this works for you.
static int ib_cmpfunc (const void *a, const void *b) {
  const ib_arrayelement* aa = reinterpret_cast<const ib_arrayelement*>(a);
  const ib_arrayelement* bb = reinterpret_cast<const ib_arrayelement*>(b);
  if ( aa->ib_blackaddr - bb->ib_blackaddr > 0) return 1;
  if ( aa->ib_blackaddr - bb->ib_blackaddr < 0) return -1;
  return 0;
}

Open in new window

0
 
LVL 26

Author Comment

by:Dr. Klahn
Doesn't seem to be available on my system, at least not with the includes I'm using.  Perhaps it's only available in C++ ?

root@www: cc test.c
test.c: In function 'ib_cmpfunc':
test.c:22:31: error: 'reinterpret_cast' undeclared (first use in this function)
   const ib_arrayelement* aa = reinterpret_cast<const ib_arrayelement*>(a);
                               ^
test.c:22:31: note: each undeclared identifier is reported only once for each function it appears in
test.c:22:48: error: expected expression before 'const'
   const ib_arrayelement* aa = reinterpret_cast<const ib_arrayelement*>(a);
                                                ^
test.c:23:48: error: expected expression before 'const'
   const ib_arrayelement* bb = reinterpret_cast<const ib_arrayelement*>(b);

Open in new window

0
 
LVL 32

Accepted Solution

by:
phoffric earned 500 total points
Right, C, not C++.

static int ib_cmpfunc (const void *a, const void *b) {
  const ib_arrayelement* aa = (const ib_arrayelement*)(a);
  const ib_arrayelement* bb = (const ib_arrayelement*)(b);
  if ( aa->ib_blackaddr - bb->ib_blackaddr > 0) return 1;
  if ( aa->ib_blackaddr - bb->ib_blackaddr < 0) return -1;
  return 0;
}

Open in new window

0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 26

Author Comment

by:Dr. Klahn
Thanks very much, phoffric.  The second version of the compare function reversed the array, but there was no compile error.  Shortly after reviewing (again, but at least for the last time) some qsort compare example functions I ended up with this:

static int ib_cmpfunc (const void *a, const void *b) {
  const ib_arrayelement* aa = (const ib_arrayelement*)(a);
  const ib_arrayelement* bb = (const ib_arrayelement*)(b);
  if (aa->ib_blackaddr > bb->ib_blackaddr) return 1;
  if (bb->ib_blackaddr > aa->ib_blackaddr) return -1;
  return 0;
}

Open in new window


And it works as hoped-for, the masks are still "attached" to their CIDR blocks as the array is sorted.

mod_ipblock:  Blacklist dump
  Entry 0 38.38.38.0 mask 255.255.255.0
  Entry 1 38.38.0.0 mask 255.255.0.0
  Entry 2 38.0.0.0 mask 255.0.0.0
  Entry 3 255.255.255.255 mask 255.255.255.255
  Entry 4 87.87.232.0 mask 255.255.255.0
  Entry 5 16.255.0.0 mask 255.255.252.0
mod_ipblock:  Blacklist dump
  Entry 0 16.255.0.0 mask 255.255.252.0
  Entry 1 38.0.0.0 mask 255.0.0.0
  Entry 2 38.38.0.0 mask 255.255.0.0
  Entry 3 38.38.38.0 mask 255.255.255.0
  Entry 4 87.87.232.0 mask 255.255.255.0
  Entry 5 255.255.255.255 mask 255.255.255.255

Open in new window

0
 
LVL 26

Author Closing Comment

by:Dr. Klahn
Glad to have this one out of the way.  Excellent support from phoffric.
0
 
LVL 32

Expert Comment

by:phoffric
Glad to have helped.
Keep in mind for future reference that the . operator has higher precedence that the (type) operator.
http://en.cppreference.com/w/c/language/operator_precedence
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
How to get all the API from website? 11 104
smtp c source code 7 85
simplest php form 3 80
Vector, list Questions R 6 30
Although it can be difficult to imagine, someday your child will have a career of his or her own. He or she will likely start a family, buy a home and start having their own children. So, while being a kid is still extremely important, it’s also …
Today, the web development industry is booming, and many people consider it to be their vocation. The question you may be asking yourself is – how do I become a web developer?
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

789 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question