Byte and double byte numerals

Started by
8 comments, last by alvaro 9 years, 4 months ago

Is there a way to Postfix a letter to a numeral, like in the case of a long integer: 2344532L, but for indicating a byte sized numeral?

Intel Core 2 Quad CPU Q6600, 2.4 GHz. 3GB RAM. ATI Radeon HD 3400.
Advertisement

What exactly are you trying to achieve?

Is there anything wrong with

"unsigned char x = 255;" ?

Do you have a code sample to show what is your intention?

Yes.

For example, If:


#include <stdint.h>

int main()
{
    uint8_t var = 0xFF;
    uint16_t var2 = var<<8;
    return 0;
}

Checking with the debugger the value of var2 after executing its initialization is 0xFF00, which makes me deduce that the compiler transformed var to a uint16_t or bigger when the bit shift happens.

Intel Core 2 Quad CPU Q6600, 2.4 GHz. 3GB RAM. ATI Radeon HD 3400.
Such suffixes are not needed for byte-sized integers, hence they do not exist. Probably the best way to document that your literal is supposed to be a byte is to write it in hexadecimal with exactly two digits, e.g. 0xFA, 0x0D, etc.. (edit) read up on the "usual arithmetic conversions" in C if you don't understand why you get 0xFF00 in your snippet above.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Yes.

For example, If:


#include <stdint.h>

int main()
{
    uint8_t var = 0xFF;
    uint16_t var2 = var<<8;
    return 0;
}

Checking with the debugger the value of var2 after executing its initialization is 0xFF00, which makes me deduce that the compiler transformed var to a uint16_t or bigger when the bit shift happens.

The value would be expected to be 0XFF00 since it was a 16-bit sized variable that would have held 0x00FF had you not applied the bitshift.

Yes.
For example, If:


#include <stdint.h>

int main()
{
    uint8_t var = 0xFF;
    uint16_t var2 = var<<8;
    return 0;
}
Checking with the debugger the value of var2 after executing its initialization is 0xFF00, which makes me deduce that the compiler transformed var to a uint16_t or bigger when the bit shift happens.


`0xFF' has type int. Then you assign it to `var', which gives `var' the value you expect. So by the time you evaluate `var<<8' it doesn't matter what type the constant had. The reason why you get `0xFF00' instead of `0x0000' as a result can be found in the integer promotion rules. Here's the first match I got in Google: https://www.securecoding.cert.org/confluence/display/seccode/INT02-C.+Understand+integer+conversion+rules

When asking questions like that, it is often better to go directly to the standard rather than to people's interpretation of the standard. You can reference the draft version of the standard that was approved. There are only minor differences between it and the final approved version, like the page headings and the front page.

Take a look at the language grammar that handles integer constants (6.4.4.1).

The only allowed suffix in C are:

u or U - meaning unsigned

l or L - meaning "long", typically a 32-bit number

ll or LL - meaning "long long", typically a 64-bit number.

If you don't have a suffix and the number is small enough to fit inside an int, the numeric constant is an int. If you assign it to a char (which the uint8_t type is under the hood), the value is automatically and silently truncated.

The conversion and promotion rules can lead to lots of fun conditions, several of them are documented in the standard itself.

If you are using uint8_t you can get several interesting effects. Consider:


uint8_t a, b;
/* ... */
uint8_t c = a + b;

According to the arithmetic rules, the values for a and b are both promoted to unsigned integers before the addition takes place, then the result is silently truncated back to an 8-bit value. This can be important for large values of a and b since it may not overflow as you expected.

Not understanding the conversion rules can lead to all kinds of subtle and potentially unexpected (e.g. buggy) behavior.

Edit: Note that C++ has similar but slightly different conversion rules. Any time you play fast-and-loose with types and conversions the rules for automatic conversions and promotions can cause unexpected bugs. As another prime example, mixing 32-bit enum values with 32-bit numeric constants can lead to some unexpected trips into 64-bit land that will silently have radically different results on different compilers.

This is what i get with VS13:


				uint8_t var = 0xFF;
00346602  mov         byte ptr [ebp-51h],0FFh  
				uint16_t var2 = var << 8;
00346606  movzx       eax,byte ptr [ebp-51h]  
0034660A  shl         eax,8  
0034660D  mov         word ptr [ebp-60h],ax  

When you load the value from var into the register, it doesn't care how large the variable was, the value from it now resides in a 32/64 bit register. When it does the shift, it's doing it in a 32/64 bit context. Storing it into var2 just means it's going to take the bottom 16bits, truncating if necessary.

devstropo.blogspot.com - Random stuff about my gamedev hobby

This is what i get with VS13:


				uint8_t var = 0xFF;
00346602  mov         byte ptr [ebp-51h],0FFh  
				uint16_t var2 = var << 8;
00346606  movzx       eax,byte ptr [ebp-51h]  
0034660A  shl         eax,8  
0034660D  mov         word ptr [ebp-60h],ax  

When you load the value from var into the register, it doesn't care how large the variable was, the value from it now resides in a 32/64 bit register. When it does the shift, it's doing it in a 32/64 bit context. Storing it into var2 just means it's going to take the bottom 16bits, truncating if necessary.

I would understand it in 32 bit machines, word is 16 bits, so the last assembly statement assigns the first 16 bits of the 32 bit register eax to var2(hence it uses ax.)
But in 64 bit machines, is eax 64 bits and ax 16bits?

Intel Core 2 Quad CPU Q6600, 2.4 GHz. 3GB RAM. ATI Radeon HD 3400.

But in 64 bit machines, is eax 64 bits and ax 16bits?


Since the 80386, eax is always a 32-bit register, whose lower 16 bits form ax. In AMD64-compatible machines, rax is a 64-bit register whose lower 32 bits form eax.

But your question was about the C language, so I don't know what we are doing talking about processor registers.

This topic is closed to new replies.

Advertisement