Anatomy of integer types in C

Integer types in C may present subtle traps (sic!) that many people are not aware of when doing seemingly simple things like ~0 or

(1 << (sizeof(int)*CHAR_BIT - 1))

Most times, on almost all processors these will produce the desired effects, but sometimes such a code will fail, crash, spit a lot of warnings. I will try to analyze this a bit, to show what may go wrong, here, and how you can get around a lot of possible problems.
Continue reading “Anatomy of integer types in C”

struct tags are not identifiers in C++

It seems a common mistake to think that a declaration like struct toto { ... }; in C++ implies the definition of the identifier toto as a type. In reality the rule for this is much more subtle than that: it only implies some sort of implicit typedef struct toto toto;. When and if in the corresponding scope there is no other identifier of the same name the toto refers to the struct.

This comes e.g in effect when you try to use the tools from “sys/stat.h” in C++. It defines a function stat and a struct stat that coexist in the same scope.

This kind of implicit definition is a pitfall when you think of code sharing between C and C++. In the following we will consider four codes that are slight variations of the same idea.

/* Compiles in C and C++, output will usually differ for both*/
#include <stdio.h>
static char T = 'a';
int main(int argc, char** argv) {
    struct T { char X[2]; };
    printf("size of T is %zu\n", sizeof(T));
}

Here the implicit typedef in C++ comes to its full beauty: for C++ the sizeof operator refers to the type and not to the variable. Thus the output in C will be 1 (this is a char variable, not a character literal) and in C++ it will at least be 2.

/* Compiles in C and C++, output will be 1 for both*/
#include <stdio.h>
int main(int argc, char** argv) {
    static char T = 'a';
    struct T { char X[2]; };
    printf("size of T is %zu\n", sizeof(T));
}

In this example, the variable T in the function scope inhibits the lookup of T as a struct tag . So the sizeof operator will refer to the variable in both languages. Since sizeof(char) is always 1 in both cases, this is what will always be printed.

/* Compiles in C but not in C++ */
#include <stdio.h>
static char T = 'a';
int main(int argc, char** argv) {
    struct T { char X[2]; };
    printf("size of T is %zu\n", sizeof T);
}

Here T will be interpreted differently by C and C++ as in the first example. Since the keyword sizeof is only valid as a prefix expression before another expression and not in front of a type, this is invalid code in C++.

/* Compiles in C and C++, output will be 1 for both*/
#include <stdio.h>
int main(int argc, char** argv) {
    static char T = 'a';
    struct T { char X[2]; };
    printf("size of T is %zu\n", sizeof T);
}

This last example is equivalent to the second, only that omitting the parenthesis in the sizeof expression ensures that T is not taken as a type, here.

Things get even worse. If you define an object with the same name later in the code, the output changes:

/* Compiles in C and C++, output will usually differ for both*/
#include <stdio.h>
static char T = 'a';
int main(int argc, char** argv) {
  struct T { char X[2]; };
  printf("size of T is %zu\n", sizeof(T));
  static char T = 'a';
  printf("size of T is %zu\n", sizeof(T));
}

In C++ this prints two different values.

This answer on stackoverflow may give you further insight into this question.

Why sem_t is not suited as an atomic counter

C has itself no primitive for atomic access to variables. Whenever we want to deal with some sort of counter in a threaded environment (e.g for reference counting) we have thus to be careful not to erase data that other threads might have written or be just in the course of reading.

sem_t as a counter

At a first glance, sem_t seems to fit into that need. It has an increment function sem_post, a decrement sem_trywait and a value test with sem_getvalue. If we are careful about interrupt handling (see this post) this should give us access to a “good” counting device, one might think.

First if we would like to do this an implementation of a reference counter would be relatively tedious. sem_t is meant to be waited for if the counter is 0, but here we would need it the other way round: we would need to wait until the counter falls to 0. Nevertheless this is doable, not with one semaphore but with several.

Side effects

What is more annoying is a another defect of sem_t its ill-conceived API, namely its tendency to have side effects to the system call. The sem_trywait call can be used to decrement a counter without waiting, and in particular to know once the counter has reached 0. If the counter has been decremented, so it was not 0 before, sem_trywait returns 0, otherwise it returns -1.

But the later case has a side effect: errno is set to an error code. So in that case, the caller has not only to do what he has to do but also has to do repair work, namely reset errno to 0. This may sound harmless, but it isn’t: errno is not a simple variable but an

expression which expands to a modifiable lvalue that has type int

This must be so, since errno is guaranteed to be different per thread, one thread’s errno wouldn’t influence the one of another thread. C has no concept of thread-only variables, therefore the system usually as to deploy quite a machinery to achieve a suitable mechanism.

So generally the use of sem_t might turn out to be quite inefficient for such a purpose.

Alternatives

If the API for the function would have gone a different way, namely in returning the precise error code instead of -1, this would be much simpler to handle. No access to pseudo-global variables would be necessary, no side effects would take place.

This strategy has been chosen for the other POSIX lock primitives such as pthread_mutex_t or pthread_rwlock_t.
Both are suitable for the purpose. An implementation with one pthread_mutex_t, one pthread_cond_t and an unsigned should be relatively obvious.

pthread_rwlock_t is even directly suitable for a locking structure for resource control. Just have all users of a resource issue a pthread_rwlock_rdlock when they start to use it and a pthread_rwlock_unlock when they cease to do so. If the resource is unused may then simply tested by a call to pthread_rwlock_wrlock.