Petr Skocik
Petr Skocik

Reputation: 60107

Sorting a Unix environment in C

I tried sorting my environment.

My C++ version (the std::sort line along with the CstrLess class) works, but the qsort version fails. What am I doing wrong?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
extern char** environ;


struct CstrLess{
  bool operator()(const char* s1, const char* s2){ return ::strcmp(s1,s2)<0; }
};

int main(){
  char** env = environ;
  size_t sz = 0;
  for(;*env; env++,sz++) {;} //measure the env

  //?
  qsort(environ, sz, sizeof(char*), (int (*)(const void*, const void*)) strcmp);

  /*std::sort(environ, environ + sz, CstrLess{});*/

  env = environ;
  while(*env){
    printf("%s%c", *env++, '\0');
  } 

  return 0;
}

Upvotes: 0

Views: 74

Answers (2)

Lundin
Lundin

Reputation: 214495

A pointer to strcmp is of type int(*)(const char *, const char *).

The type expected by qsort is int(*)(const void*, const void*).

Wild function pointer conversions is undefined behavior. Your compiler would rightfully have given you a warning/error if you hadn't silenced it with the ugly cast. It is possible that there could be different calling conventions for the different types, so this undefined behavior is a valid concern.

The correct approach is to write a wrapper function and pass a pointer to that instead:

int strcmp_wrapper (const void* s1, const void* s2)
{
  return strcmp(s1, s2); // implicit conversion from const void* to const char*.
}

Upvotes: 1

ecatmur
ecatmur

Reputation: 157424

qsort passes its comparison function pointers to the elements to be compared; you need to indirect that pointer to get the char const* pointers to be passed to strcmp:

qsort(environ, sz, sizeof(char*),
    [](const void* a, const void* b) {
        return strcmp(
            *reinterpret_cast<const char**>(a), *reinterpret_cast<const char**>(b)); });

Pure C solution:

int qsort_strcmp(const void* a, const void* b) {
    return strcmp(*(const char**)(a), *(const char**)(b));
}

// ...

  qsort(environ, sz, sizeof(char*), qsort_strcmp);

Upvotes: 2

Related Questions