-1

I paste a rule from Michael Barr Coding style book down below.

I found two "mistakes" on sentence: #if ((8 != sizeof(timer_reg_t))

  1. Michael is using a sizeof(), executed at compilation time, on a preprocessor instruction, so far I know it won't ever works, indeed I got the message:

error: missing binary operator before token "("

Am I missing something?

  1. The second issue is a missing')'; I think it is only a mistyping error.

The complete rule is here:

5.5 Structures and Unions Rules: a. Appropriate care shall be taken to prevent the compiler from inserting padding bytes within struct or union types used to communicate to or from a peripheral or over a bus or network to another processor. b. Appropriate care shall be taken to prevent the compiler from altering the intended order of the bits within bit-fields. Example:

typedef struct
{
uint16_t count; // offset 0
uint16_t max_count; // offset 2
uint16_t _unused; // offset 4
uint16_t enable : 2; // offset 6 bits 15-14
uint16_t b_interrupt : 1; // offset 6 bit 13
uint16_t _unused1 : 7; // offset 6 bits 12-6
uint16_t b_complete : 1; // offset 6 bit 5
uint16_t _unused2 : 4; // offset 6 bits 4-1
uint16_t b_periodic : 1; // offset 6 bit 0
} timer_reg_t;
// Preprocessor check of timer register layout byte count.
#if ((8 != sizeof(timer_reg_t))
# error “timer_reg_t struct size incorrect (expected 8 bytes)”
#endif
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • `#if (( ())` is not balanced. – tadman Feb 21 '23 at 16:27
  • 1
    sizeof is interpreted by the compiler not the preprocessor, you can not check it like in preprocessor step. and as others mentioned you paranthesis are not balanced too – amirhm Feb 21 '23 at 16:32
  • Looks like C23's `static_assert(sizeof(timer_reg_t) == 8, "timer_reg_t struct size incorrect (expected 8 bytes)");` would come in handy. – Ted Lyngmo Feb 21 '23 at 16:34
  • static_assert is from c11, why you mention 23? https://en.cppreference.com/w/cpp/language/static_assert – amirhm Feb 21 '23 at 16:41
  • @amirhm No, `_Static_assert` is from C11. `static_assert` is from C23. (You're looking at the C++ page). You could use `static_assert` in C11 too, but via a macro in `assert.h`. – Ted Lyngmo Feb 21 '23 at 16:43
  • 2
    Dear, I know brackets must be balanced, I just copy and paste like in the paper, anyway solving this issues main the problem persist. – Daniel H Sagarra Feb 21 '23 at 17:45

2 Answers2

2

You cannot evaluate the sizeof inside the preprocessor. It is evaluated by the compiler. You can simply check like this and should be fine as 8.

#include <stdint.h>
#include <stdio.h>

typedef struct
{
uint16_t count; // offset 0
uint16_t max_count; // offset 2
uint16_t _unused; // offset 4
uint16_t enable : 2; // offset 6 bits 15-14
uint16_t b_interrupt : 1; // offset 6 bit 13
uint16_t _unused1 : 7; // offset 6 bits 12-6
uint16_t b_complete : 1; // offset 6 bit 5
uint16_t _unused2 : 4; // offset 6 bits 4-1
uint16_t b_periodic : 1; // offset 6 bit 0
} timer_reg_t;


int main(){
    printf("%d \n", sizeof(timer_reg_t));
    return 0;
} 

It will print 8.

If you want to see the compile time verification, you can use a static_assert (from <assert.h>) as well:

static_assert(sizeof(timer_reg_t) == 8, "sizeof(timer_reg_t) != 8");
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
amirhm
  • 1,239
  • 9
  • 12
  • 1
    Note that you'd need `#include ` to use `static_assert` in C18 while `_Static_assert` does not require including any headers. – Ted Lyngmo Feb 21 '23 at 16:46
  • 1
    `%d` is the wrong specifier to print a value of type `size_t`. Use `%zu` instead. – Ian Abbott Feb 21 '23 at 17:30
  • Thank you , your approach is a good one, but I am still wondering how an experienced programmer like Michael Barr could have published that sentence. I am wondering if there is something else I am missing – Daniel H Sagarra Feb 21 '23 at 17:34
  • 1
    It's a bug, @DanielHSagarra — an oversight which shows that the code shown in the final version of the book was not proofread by a compiler. – Jonathan Leffler Feb 21 '23 at 17:46
2

You are correct on both counts. The line you quoted from the book Embedded C Coding Standard by Michael Barr ] has exactly the problems that you have identified.

Your first concern for the line #if ((8 != sizeof(timer_reg_t)) (maintaining original line which is missing a closing parenthesis) is a serious one. Just as you indicated, the sizeof would be evaluated at compile time, i.e. post pre-processing time. Not only is the value not available then, pre-processor directives have already been processed and are gone at the time sizeof could be given a value. In fact, as long as neither sizeof or timer_reg_t have not been #define'd as symbolic constants, the preprocessor will see each of them as 0, effectively giving you #if ((8 != 0(0)) which is neither functional nor resembles the actual intent.

The answers to this post as well as amirhm's answer here show ways that the goal of Michael Barr in that section of his book can be achieved.

Your second concern, that of a missing ')', is also valid. I would classify it as a minor typo that would need to be fixed, but not of great consequence.

Avi Berger
  • 2,068
  • 1
  • 18
  • 13