37

It seems reasonable to assume that T and const T would be two types that would be the same size and have the same alignment, but after thinking about some real systems, it seems that they could be different.

Let me explain:

Suppose you have a system with two types of memory: RAM and Flash (which is read only). The RAM is 8 bit addressable, while the Flash is only 16 bit addressable. Suppose this is T:

struct T
{
  uint8_t x;
  uint16_t y;
};

In the byte addressable RAM this struct would be 3 bytes long.... but in the double byte addressable Flash (which is where a const variable would reside) this struct would have to be at least 4 bytes long, because of alignment issues.

So here is my question:

Do the c and c++ standards guarantee the sizes and alignment of const and nonconst types?

DarthRubik
  • 3,927
  • 1
  • 18
  • 54
  • You're making lots of assumptions that aren't guaranteed by anyone. Most of the RAM vs flash stuff comes from your linker script anyway. – Jonathon Reinhart Aug 06 '16 at 02:08
  • 10
    @JonathonReinhart Hence the question – DarthRubik Aug 06 '16 at 02:08
  • 3
    This question is tricky. The answer is "yes, they have to be the same size," however, flash is **not** "where `const variable would reside`. It may be that you put a lot of const values there, but const does not mean flash. in particular, I can have a `const int` argument to a function call, which will be on the stack, not in flash. In the end, I believe such a system violates the C memory model, which is homogenous, so its behavior would be a compiler extension. – Cort Ammon Aug 06 '16 at 03:19
  • Note that fancy hardwares like the one you describe most often come with *custom, non conforming* compilers that are able to exploit the full hardware potential at the cost of non-conforming to some details in the standard... So if you really need to make use of that Flash v RAM thing you can still use the non conforming compiler. – Bakuriu Aug 06 '16 at 09:58
  • 2
    @CortAmmon I disagree with your statement "I believe such a system violates the C memory model, which is homogenous". Yes C has an abstract memory model which is homogenous, but the C standard does not require that the implementation have a homogenous memory, only that it *act* like it did. One way the compiler could get around this issue (at the cost of optimization) and act like it had homogenous memory, would be to make all `T`s 4 bytes long, and pointers to `T` have a special bit in them that indicates whether it is located in flash or RAM..... – DarthRubik Aug 06 '16 at 12:38
  • To iterate @DarthRubik point about a memory model: I'm currently coding for a platform with 14-bit Flash words and 8-bit RAM words. (The RAM itself being split up in banks of 128 bytes each, but only 80 bytes in each bank are available). It stores `const`-data in the Flash, and as an obedient C developer, I don't care _how_ it stores it (even though I know). As long as I can access the data using the normal C constructs, my code works as expected. – pipe Aug 06 '16 at 15:08
  • @pipe So does it just waste the extra 6 bits for every byte it stores? – DarthRubik Aug 06 '16 at 15:11
  • @DarthRubik Yes, and even worse, the only instruction that can read from Flash is called `RETLW`, return with literal. To fetch a byte from the Flash it has to _jump_ to one of those instructions stored in Flash, and then that instruction will return with the byte you wanted. For every byte. It's still worth it when you only have a total of 224 bytes of precious RAM... – pipe Aug 06 '16 at 15:15
  • @pipe What is the micro you are using? – DarthRubik Aug 06 '16 at 15:17
  • @DarthRubik It's called the [PIC16F628](http://www.microchip.com/wwwproducts/en/PIC16F628A). Chapter 3 and 15 in the [documentation](http://ww1.microchip.com/downloads/en/DeviceDoc/40044G.pdf) explains this horrible architecture. It's very old, but sadly they still produce a lot of variants with this instruction set. – pipe Aug 06 '16 at 15:24
  • Correct me if I'm wrong, but unless you manually specify alignment, won't `T` be 4 bytes regardless of where it's stored? It would appear that `y` requires 2-byte alignment, while `x` is only 1 byte, so there would be an alignment byte if `x` is before `y`. Or does your system's PIC's compiler default to 1-byte alignment? – Justin Time - Reinstate Monica Aug 06 '16 at 17:10
  • @JustinTime On the 8 bit RAM, there typically is no alignment issues, because the largest addressable data type is a byte, so you can easily have any data put anywhere (which is why 8 bit micro controllers, are so popular------they make life simple) – DarthRubik Aug 06 '16 at 20:26
  • @DarthRubik Ah. Didn't think about that, it _does_ make things a lot simpler. My mistake, then. – Justin Time - Reinstate Monica Aug 06 '16 at 20:30
  • See also http://stackoverflow.com/questions/8568432/is-gccs-attribute-packed-pragma-pack-unsafe –  Aug 07 '16 at 08:26

3 Answers3

34

Section 3.9.3:

The cv-qualified or cv-unqualified versions of a type are distinct types; however, they shall have the same representation and alignment requirements (3.11). 53

"cv-qualified" here refers to const and volatile. So the answer is, yes.

const and volatile only specify the limitations/attributes of access to the specified object. They are not considered to be a part of the base type itself; hence they cannot affect the type's properties.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • 1
    So in my example the `sizeof(T)` would be forced to 4 in order to match the `const T`? – DarthRubik Aug 06 '16 at 02:11
  • And for C it's 6.2.5/26 (in C11) except spelling is `_Alignof` – dave_thompson_085 Aug 06 '16 at 07:41
  • 1
    @DarthRubik Unlike Sam, I'm not sure that follows. The compiler could alternatively force the object to be stored in a region of memory that allowed the less strict 3-byte alignment. Of course, this effectively means disallowing use of the flash memory in your example - but I don't think that's as outlandish as it sounds; I seem to recall Arduino requires special serialisation of data in defined units to/from Flash. The only point is that the compiler can't allocate different cv-qualified incarnations such that the mentioned attributes differ. I wouldn't rush to conclude _how_ it must do this. – underscore_d Aug 06 '16 at 07:54
  • @underscore_d If you use `avr-gcc` (which is what arduino uses), `gcc` tries to put `const` variables in flash, but using `FLASHCONST` guarantees it. – DarthRubik Aug 06 '16 at 13:16
31

Yes, this is guaranteed by [basic.type.qualifier] / 1

The cv-qualified or cv-unqualified versions of a type are distinct types; however, they shall have the same representation and alignment requirements (3.11).

user657267
  • 20,568
  • 5
  • 58
  • 77
4

In the byte addressable RAM this struct would be 3 bytes long.... but in the double byte addressable Flash (which is where a const variable would reside) this struct would have to be at least 4 bytes long, because of alignment issues.

However, the compiler cannot infer that just because it's const here, it is stored in ROM. There's lots of other things that can prevent that, like mutable, or you could just dynamically place the const T on the stack or manually place it into heap memory in RAM or a thousand other things. You could also have a const T& that could be in either location.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • This is good information. It's good to remember that `const` does not _guarantee_ placement in ROM/Flash, although that's often what you want. – pipe Aug 06 '16 at 15:01
  • Well `mutable` is relevant as a mutable field inside a `const` object can be modified and thus cannot reside in ROM. – Phil1970 Aug 06 '16 at 19:13