Home > Back-end >  Does integer promotion take up more memory?
Does integer promotion take up more memory?

Time:01-11

I heard that C converts any data type that have less bytes than integer to the type integer . Does that affect the memory too ? for example if i have a char c , that should take up 1 byte in the memory . Will the char c take sizeof(int) bytes in memory after integer promotion ? or is the integer promotion only done in operations , therefore it doesn't affect the memory ?

CodePudding user response:

Integer promotions are used only in the evaluation of expressions, not in the storage of objects.

As with most things in the C standard, there are at least two levels in which the standard specifies behavior: The computations are described using a model of an abstract computer that performs the calculations literally as the standard describes. But actual C implementations may perform the calculations in any way that gets the same observable behavior (largely input/output interactions and uses of volatile objects). So expression evaluation will get the same results as if integer promotions were used, but, when it comes to storing objects, the compiler has a great deal of liberty.

For local variables (automatic objects declared inside functions), the compiler may keep them in registers and/or on the stack. When the value of an object is in a register, it will generally occupy the whole register, so a whole 32-bit register may be used for an eight-bit char object. On the stack, a compiler might or might not “pack” objects, depending on the nature of the target processor and optimization settings. So we might find char objects occupying just a single byte each on the stack, or we might find them occupying 32-bits, or other possibilities.

However, for arrays of objects, a compiler will generally use the nominal size of the object. An array of n char will use n bytes, and an array of n 16-bit short will use 2n eight-bit bytes, and so on. There can be exceptions to this. For example, if the compiler fully optimizes the uses of an array that has only a very few elements, the resulting generated code might be as if the array elements were individually declared objects. However, in many situations, the compiler has no choice: If an array is passed to a routine in another translation unit, the compiler must present the array in memory in its formally defined form. For arrays of char or short, those will be contiguous elements of their nominal size, not promoted.

CodePudding user response:

No. Promotion is a conceptual operation, not something that actually changes the original variable in memory.

If the variable is being used as an argument to a function or operand of an operator, promotion happens when the variable's value is being copied into a CPU register or the memory location of the function parameter. That destination will already have the larger size. The original value is still its original size.

CodePudding user response:

It seems you are mis-matching c types size in "memory" and memory alignment.

C types have fixed size (but for compiler-specific types.. well, it depends on the compiler). Let's stick to C types. For instance uint16_t is expected to be 16bits, always! That is same for other types. You can get the actual size of a type with sizeof(). It works for standard types, for structures, etc.

Memory alignment is about "how data are installed into the memory". For instance, if you want a 16bits data be aligned on a 32bits boundary, then the compiler will put the data at the start of 32bits memory address.

Depending on the compiler optimizations and what is put just before your data, you may lose up to 24bits of memory..

With GCC, memory alignment can be changed with __attribute__((ALIGNED(8))) put after the variable declaration and where 8 is the number of bytes to align to. In this case, 8 implies a 64bits alignment.

Note that beyond this "user" point of view, the compiler can perform any optimizations it wants as long as the target behavior is consistent. I mean, your data can take more space that it needs, or just the necessary amount!

CodePudding user response:

C was designed for a 16-bit machine which included instructions that could load or store half of a 16-bit word, but otherwise used 16-bit operations for everything. Given something like char1 = (char2 char3) >> 1;, making the code behave as though the addition and shift used 8 bit values would have required including an extra step to truncate the result of the 16-bit addition.

While some machines that are targeted by C compilers are able to process 8-bit operations faster than 16-bit operations, compilers for such machines often include logic that checks whether the upper half of a computation will ever be observed, and omit operations that would compute it if it isn't. Thus, given something like:

unsigned char a,b,c;
a=b c;

the compiler will notice that while it would be possible for b c to yield a value which exceeds 255, and whose top half would thus be non-zero, the assignment to a will discard the top half of the value being stored and there would thus be no need to compute it. On the other hand, given something like:

if (a b > c)

a compiler would be required to either compute a 16-bit value for (a b) and compare that with c, or else generate code which would use a machine's 8-bit add instruction to add b to a, check whether there was a carry, and if not compare the result against c; if the original computation carried, the comparison could be skipped, since the result would be known to be greater than the largest value c could hold.

For the most part, promotion simplifies compilers while making life nicer for programmers. The main gotchas arise in situations which compilers had handled sensibly in the days before the Standard, and which implementations were expected to continue handling sensibly, but where some compilers go out of their way not to respect such precedent. For example, if int is 32 bits and unsigned short is 16 bits, compilers would traditionally have processed:

uint1 = ushort1 * ushort2;

in a manner that was agnostic as to whether unsigned short values were promoted to a signed int or unsigned int; the authors in the Standard observed in the published Rationale that implementations for quiet-wraparound two's-complement machines would compute a value which, when converted to unsigned, would yield the correct result even if the mathematical product was greater than INT_MAX. If the gcc compiler observes, however, that such a computation would produce a value greater than INT_MAX if certain inputs were received, it may go out of its way to avoid generating code that would process such inputs meaningfully.

  •  Tags:  
  • c
  • Related