0

Consider the following example:

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

struct mystruct_s {
  uint16_t first;
};
typedef struct mystruct_s mystruct_t;

#define THEVALUE 5
const mystruct_t mytester = {
  .first = THEVALUE,
};

struct otherstruct_s {
  uint16_t initial;
};
typedef struct otherstruct_s otherstruct_t;

otherstruct_t othertester = {
  .initial = mytester.first,
};

int main() {
  printf("Hello, world %d!\n", othertester.initial);
  return 0;
}

When I build this in https://replit.com/languages/c I get:

> clang-7 -pthread -lm -o main main.c
main.c:20:23: error: initializer element is not a
      compile-time constant
  .initial = mytester.first,
             ~~~~~~~~~^~~~~
1 error generated.
exit status 1

I was kind of hoping, that since mytester is declared const, and its its .first field is initialized through a define, the compiler would have figured out that I want the same initialization applied to othertester.initial, but apparently not.

In my actual code, gcc was highlighting mytester, while here clang did in fact point to the field by highlighting, which indeed is not const - is this why I cannot initialize in this case?

Anyways, I have a similar (though much more convoluted) actual case; and while I'm aware that I can just use the define to initialize, I would really like to instead initialize via mytester.first for readability. Is there any workaround where I can use that, without having to define a copy of mystruct_s where the .first field is const?

sdbbs
  • 4,270
  • 5
  • 32
  • 87
  • 1
    I just compiled and ran your posted code without issue. gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0. – Simon Goater Jan 11 '23 at 12:37
  • 3
    Fundamentally, the reason is that allowing objects to be initialized with other objects, even if they are `const`, would require the compiler to track what is stored in objects. Nothing in the C standard currently requires this—all the initializers a compiler is required to support are either values the compiler can compute directly from “compile-time constants” (essentially literals and expressions of them) or things the linker/loader can fill in (addresses). – Eric Postpischil Jan 11 '23 at 12:38
  • 2
    @SimonGoater And...? gcc is notoriously a non-conforming non-C compiler unless you explicitly use `-std=c17 -pedantic-errors`. – Lundin Jan 11 '23 at 12:42
  • 2
    Although soon to be standard C (C23): `otherstruct_t othertester = { .initial = (constexpr mystruct_t) { .first = THEVALUE }.first };` gcc (trunk) `-std=c2x` accepts it. – Lundin Jan 11 '23 at 12:47
  • Thanks all, good to be aware there is more difference in compilers than I realized at first ... – sdbbs Jan 11 '23 at 12:49
  • Thanks @EricPostpischil - good explanation of why the OP approach did not work; could be an answer – sdbbs Jan 11 '23 at 12:50
  • Thanks @Lundin - that soon-to-be-standard would have been great; although if it is "soon-to-be", I guess there is no other current workaround, but to just use the define – sdbbs Jan 11 '23 at 12:51
  • 1
    @sdbbs You could download a _very_ recent gcc build (gotta be newer than 12.2) for your system and use `-std=c2x` until formal release. `constexpr` will be in it since it has been voted through by the committee. The standard just needs to be formalized and then every compiler vendor has to implement all the new features. – Lundin Jan 11 '23 at 12:53
  • 1
    Or just use https://godbolt.org/ with "x86-64 gcc (trunk)", that's what I just did. – Lundin Jan 11 '23 at 12:55

0 Answers0