Showing posts with label gcc. Show all posts
Showing posts with label gcc. Show all posts

Wednesday, May 16, 2018

Pre-processor token concatenation that involves operators

Recently encountered this problem

#define call_fn(var) myfn(mystruct->var)
call_fn(size)

This resulted in an error. (Use gcc -E only to do pre-processing)

error: pasting "->" and "size" does not give a valid preprocessing token
 #define call_fn(var) myfn(mystruct->##var)

Had to search this a bit to find the reason. The reasons that I found are summarized below.

  • Result of token concatenation should result in a single valid token.
    • Here, mystruct->size (the result of operation) is not s single token. It is actually 3 tokens: "mystruct", "->" and "size"
  • gcc is more stringent than VC++ in evaluating this. So, something that works on VC++ might not work here
So, what is the solution?

Imaging you had to do an add macro. What would you have done?

#define ADD(a,b) (a+b)

As I understand, the same principle applies here. This is what I need to do


#define call_fn(var) myfn(mystruct->var)
call_fn(size)
This will give the expected result: (Use gcc -E only to do pre-processing)

myfn(mystruct->size)

Tuesday, February 2, 2010

The alignment magic

We faced some trouble with assignment of memory to some structures. We did an mmap and allocated memory to different variables and structures. These variables and structures were defined in random order. There were some variables and some structures followed. This caused the problem of memory alignment. So, today, I did a bit of reading on memory alignment and the program that you see below is the result of that reading.

#include <stdio.h>

typedef struct {
    unsigned char uc;
}TST1;

typedef struct {
    unsigned char uc;
    unsigned short us;
}TST2;

typedef struct {
    unsigned char uc;
    unsigned short us;
    unsigned int ui;
}TST3;

typedef struct {
    unsigned char uc;
    unsigned short us;
    unsigned int ui;
} TST4 __attribute__ ((aligned(2)));

#define PRN_ALIGN(x) printf("Alignment of %s is %d \n",#x, __alignof__ (x))

int main()

{

    PRN_ALIGN(TST1);
    PRN_ALIGN(TST2);
    PRN_ALIGN(TST3);
    PRN_ALIGN(TST4);

    return 0;
}

You can clearly see that the alignment varies for different structures. The way to find alignment is to use the __alignof__ (datatype). However, gcc allows you to force the alignment to be something other than the default value. That is achieved by the __attribute__ ((aligned(AlignmentValue))).

We solved our problem by re-arranging the variables. This caused the structure to appear exactly at the alignment boundary. The other solutions would have been to force all structures to have alignment of 1. Yet another solution would have been to do use the __alignof__ to find the acceptable location for placing the structure. Below code is an example using malloc

    unsigned char *memPtr;
    
    memPtr=malloc(100);

    printf("%p\n",memPtr);
    TST2 *pstMyStructure= (TST2*) (((int)memPtr / __alignof__ (TST2) + 1) * __alignof__ (TST2));
    printf("%p\n",pstMyStructure);
    memPtr = (unsigned char*)((int)memPtr / __alignof__ (TST2) + 1) + __alignof__ (TST2) + sizeof(TST2);
    printf("%p\n",memPtr);

(Do keep in mind that strictly speaking, we cannot interchange integers and pointers)