Should a cast be used to truncate a long variable?Implicit type promotion rulesRegular cast vs. static_cast...
Am I correct in stating that the study of topology is purely theoretical?
Could a warlock use the One with Shadows warlock invocation to turn invisible, and then move while staying invisible?
Closed set in topological space generated by sets of the form [a, b).
How to create a label containing values from different layers in QGIS
"Starve to death" Vs. "Starve to the point of death"
Switch case implementation in Java for an integer pair combination
Prevent Nautilus / Nemo from creating .Trash-1000 folder in mounted devices
A fantasy book with seven white haired women on the cover
Can a player sacrifice a creature after declaring that creature as blocker while taking lethal damage?
If angels and devils are the same species, why would their mortal offspring appear physically different?
Taking headphones when quitting job
How to not let the Identify spell spoil everything?
Crack the bank account's password!
Word for something that's always reliable, but never the best?
Subsurf on a crown. How can I smooth some edges and keep others sharp?
What species should be used for storage of human minds?
How can I prevent an oracle who can see into the past from knowing everything that has happened?
How vim overwrites readonly mode?
What's the oldest plausible frozen specimen for a Jurassic Park style story-line?
Is `Object` a function in javascript?
Which RAF squadrons and aircraft types took part in the bombing of Berlin on the 25th of August 1940?
Why is 'diphthong' pronounced the way it is?
Will rerolling initiative each round stop meta-gaming about initiative?
How big is a framed opening for a door relative to the finished door opening width?
Should a cast be used to truncate a long variable?
Implicit type promotion rulesRegular cast vs. static_cast vs. dynamic_castCast int to enum in C#Direct casting vs 'as' operator?When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?Do I cast the result of malloc?Safely casting long to int in JavaImprove INSERT-per-second performance of SQLite?How do I truncate a .NET string?How to truncate a foreign key constrained table?Why don't Java's +=, -=, *=, /= compound assignment operators require casting?
I have a 16 bits unsigned variable. I need to split it in 8 bits chunks.
Is doing the following enough:
chunk_lsb = (uint8)variable;
chunk_msb = (uint8)(variable >> 8);
Or should I use a mask:
chunk_lsb = (uint8)(variable & 0xFFu);
chunk_msb = (uint8)((variable >> 8) & 0xFFu);
I know that both approaches work, I'm just looking for the best way to do it, if there is one. Maybe there's none and just use the cast to reduce calculations is the best way? What do you guys think?
c casting mask truncate
add a comment |
I have a 16 bits unsigned variable. I need to split it in 8 bits chunks.
Is doing the following enough:
chunk_lsb = (uint8)variable;
chunk_msb = (uint8)(variable >> 8);
Or should I use a mask:
chunk_lsb = (uint8)(variable & 0xFFu);
chunk_msb = (uint8)((variable >> 8) & 0xFFu);
I know that both approaches work, I'm just looking for the best way to do it, if there is one. Maybe there's none and just use the cast to reduce calculations is the best way? What do you guys think?
c casting mask truncate
I think both will generate same binary code. As the first solution is more readable, I would use this one. You just need to be sure that uint8 is 8-but on all platforms (i guess it is)
– jaudo
7 hours ago
Thank you @jaudo, that's also the direction I'm taking.
– Soyding Mete
7 hours ago
11
Sidenote: Standardstdint.htypes such asuint8_tshould be preferred instead of creating your own.
– user694733
7 hours ago
add a comment |
I have a 16 bits unsigned variable. I need to split it in 8 bits chunks.
Is doing the following enough:
chunk_lsb = (uint8)variable;
chunk_msb = (uint8)(variable >> 8);
Or should I use a mask:
chunk_lsb = (uint8)(variable & 0xFFu);
chunk_msb = (uint8)((variable >> 8) & 0xFFu);
I know that both approaches work, I'm just looking for the best way to do it, if there is one. Maybe there's none and just use the cast to reduce calculations is the best way? What do you guys think?
c casting mask truncate
I have a 16 bits unsigned variable. I need to split it in 8 bits chunks.
Is doing the following enough:
chunk_lsb = (uint8)variable;
chunk_msb = (uint8)(variable >> 8);
Or should I use a mask:
chunk_lsb = (uint8)(variable & 0xFFu);
chunk_msb = (uint8)((variable >> 8) & 0xFFu);
I know that both approaches work, I'm just looking for the best way to do it, if there is one. Maybe there's none and just use the cast to reduce calculations is the best way? What do you guys think?
c casting mask truncate
c casting mask truncate
edited 7 hours ago
Soyding Mete
asked 7 hours ago
Soyding MeteSoyding Mete
524
524
I think both will generate same binary code. As the first solution is more readable, I would use this one. You just need to be sure that uint8 is 8-but on all platforms (i guess it is)
– jaudo
7 hours ago
Thank you @jaudo, that's also the direction I'm taking.
– Soyding Mete
7 hours ago
11
Sidenote: Standardstdint.htypes such asuint8_tshould be preferred instead of creating your own.
– user694733
7 hours ago
add a comment |
I think both will generate same binary code. As the first solution is more readable, I would use this one. You just need to be sure that uint8 is 8-but on all platforms (i guess it is)
– jaudo
7 hours ago
Thank you @jaudo, that's also the direction I'm taking.
– Soyding Mete
7 hours ago
11
Sidenote: Standardstdint.htypes such asuint8_tshould be preferred instead of creating your own.
– user694733
7 hours ago
I think both will generate same binary code. As the first solution is more readable, I would use this one. You just need to be sure that uint8 is 8-but on all platforms (i guess it is)
– jaudo
7 hours ago
I think both will generate same binary code. As the first solution is more readable, I would use this one. You just need to be sure that uint8 is 8-but on all platforms (i guess it is)
– jaudo
7 hours ago
Thank you @jaudo, that's also the direction I'm taking.
– Soyding Mete
7 hours ago
Thank you @jaudo, that's also the direction I'm taking.
– Soyding Mete
7 hours ago
11
11
Sidenote: Standard
stdint.h types such as uint8_t should be preferred instead of creating your own.– user694733
7 hours ago
Sidenote: Standard
stdint.h types such as uint8_t should be preferred instead of creating your own.– user694733
7 hours ago
add a comment |
4 Answers
4
active
oldest
votes
It isn't clear what type variable is. Without that specified, we can only speculate.
But in general, you should avoid bit shifting on signed integer types, as that leads to various forms of poorly-defined behavior. This in turn means that you have to be careful with small integer types too, because they get promoted to signed int. See Implicit type promotion rules.
The specific case of (uint8)((variable >> 8) & 0xFFu); is safe if variable is unsigned. Otherwise it is unsafe, since right-shifting a negative value leads to implementation-defined behavior (arithmetic or logical shift).
variable << 8 will invoke undefined behavior on 16 bit systems in case variable is a small integer type, or an int16_t.
The safest, most portable way no matter left/right shift is therefore this:
chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);
Though you might want to be overly explicit in order to silence all compiler warnings:
chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );
AFAICT(variable >> 8) & 0xFFuwill give the same result regardless of whether the shift is arithmetic or logical, as long asintis at least 16 bits wide (which I believe the standard guarantees it to be).
– Ilmari Karonen
4 hours ago
1
@IlmariKaronen The size of the variable doesn't matter for that, only the signedness. In case the value is negative, you get implementation-defined behavior. One example of such broken code would beunsigned char u = 0; ... ~u >> n;
– Lundin
4 hours ago
I agree that it's unpredictable, insofar as the standard doesn't require the implementation-defined result of right-shifting a negative signed integer to be either an arithmetic or a logical shift. However, on implementations where it is one of those two, shifting right by n bits and then masking off (at least) the n highest bits should produce the same result regardless of which kind of shift it is. Thus, your parenthetical remark in the third paragraph of your answer seems a bit misleading.
– Ilmari Karonen
3 hours ago
@Lundin, it is perhaps worthwhile to note that your first set of recommendations assumes thatchunk_lsbandchunk_msbthemselves have type equivalent touint8_t. That isn't clear from the question -- the OP's "8 bits chunks" could be stored in variables having a wider type, or a signed one.
– John Bollinger
3 hours ago
@IlmariKaronen: If the authors of the Standard had required either zero-fill or sign-extension behavior, but there had been some platform where some other behavior would have been more useful, mandating zero-fill or sign-extension behavior could have made C less useful on that platform. The only situations where it should better whether the Standard mandates those two particular behaviors would be if such a platform actually exists, or a compiler writer feels like being deliberately weird. The former case would be best accommodated by not mandating the behavior...
– supercat
2 hours ago
|
show 1 more comment
Since uint8 is unsigned, you don't have to do the masking:
6.3.1.3 Signed and unsigned integers
- When a value with integer type is converted to another integer type other than _ Bool , if the value
can be represented by the new type, it is unchanged.
- Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting
one more than the maximum value that can be represented in the new type until the value is in the
range of the new type. 60)
- Otherwise, the new type is signed and the value cannot be represented in it; either the result is
implementation-defined or an implementation-defined signal is raised.
However, most likely both will result in the same compiler output. I usually add the mask because it makes clear what code is supposed to do, and makes the cast unnecessary.
1
Except, C has nasty integer promotion, so if you try to do the same thing and left shift, the program may implode in undefined behavior. In this particular case we get away since it is right shift of a positive number.
– Lundin
7 hours ago
Also, the cast makes the loss of precision clearly intentional. Many compilers can emit warning on loss of precision, which can extremely important. (I'm thinking of noobs who are so certain that "size_tand pointers are really justunsigned int...)
– Andrew Henle
6 hours ago
@Lundin: Under C89, signed left-shift behavior was defined for all possible left-operand values on implementations whose integer types don't have padding bits or trap representations, but trapping might have been more sensible in situations where the mandated behavior would differ from that of power-of-two multiplication. I've seen no evidence to suggest any intention to change the handling of situations where C89's behavior and power-of-two multiplication would be equivalent.
– supercat
2 hours ago
@supercat It's bad enough to accidentally shift data into the sign bit, regardless of UB and signedness format.
– Lundin
49 mins ago
@Lundin: In two's-complement notation, the sign bit is simply shorthand for "the state of this bit and an infinite number of bits to the left". The value -3 is an infinite number of ones followed by 01. It may be more convenient to think of a 32-bit two's-complement value as being composed of an infinite number of 0's or 1's followed by exactly 31 more bits, but an infinite number of 1's, followed by 29 more, and then 01, is the same as an infinite number of 1's followed by 01.
– supercat
23 mins ago
|
show 1 more comment
Should a cast be used to truncate a long variable?
If chunk_lsb is an 8 bit object (narrower than variable), use cast or mask (not both). Useful in quieting pedantic warnings about range reduction. I prefer the mask - unless the compiler is picky.
uint8_t chunk_lsb = (uint8_t) variable;
// or
uint8_t chunk_lsb = variable & 0xFFu;
Otherwise use the mask.
unsigned chunk_lsb = variable & 0xFFu;
add a comment |
Maybe there's none and just use the cast to reduce calculations is the best way?
General speaking, the asm code will be the same, so in terms of speed, it does not matter which one you use:
- masking: https://godbolt.org/z/Olrw3x
- casting: https://godbolt.org/z/EEdvQZ
What do you guys think?
IMO, the first one is clearer, in terms of readability, but I cannot figure out a coding standard or guideline which supports my preference. Anyway, I would use a const variable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking (assuming that you have chosen a correct name for the const variable).
3
Anyway, I would use aconstvariable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking Anyone who thinks0xFFin the context of bit masking is a "magic number" that has to be papered over with a variable is engaging in cargo-cult programming. What possible variable can be more clear than0xFFas a bit mask?one_byte_bit_mask_0xFF?
– Andrew Henle
7 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number.
– Jose
6 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number Oh? How many bits does this mask:unsigned int result = input & mask;And no, I didn't DV.
– Andrew Henle
6 hours ago
0xFFvsone_byte_bit_mask_0xFFvsmask, I choose the second one as the least-bad option.
– Jose
6 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54866461%2fshould-a-cast-be-used-to-truncate-a-long-variable%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
It isn't clear what type variable is. Without that specified, we can only speculate.
But in general, you should avoid bit shifting on signed integer types, as that leads to various forms of poorly-defined behavior. This in turn means that you have to be careful with small integer types too, because they get promoted to signed int. See Implicit type promotion rules.
The specific case of (uint8)((variable >> 8) & 0xFFu); is safe if variable is unsigned. Otherwise it is unsafe, since right-shifting a negative value leads to implementation-defined behavior (arithmetic or logical shift).
variable << 8 will invoke undefined behavior on 16 bit systems in case variable is a small integer type, or an int16_t.
The safest, most portable way no matter left/right shift is therefore this:
chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);
Though you might want to be overly explicit in order to silence all compiler warnings:
chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );
AFAICT(variable >> 8) & 0xFFuwill give the same result regardless of whether the shift is arithmetic or logical, as long asintis at least 16 bits wide (which I believe the standard guarantees it to be).
– Ilmari Karonen
4 hours ago
1
@IlmariKaronen The size of the variable doesn't matter for that, only the signedness. In case the value is negative, you get implementation-defined behavior. One example of such broken code would beunsigned char u = 0; ... ~u >> n;
– Lundin
4 hours ago
I agree that it's unpredictable, insofar as the standard doesn't require the implementation-defined result of right-shifting a negative signed integer to be either an arithmetic or a logical shift. However, on implementations where it is one of those two, shifting right by n bits and then masking off (at least) the n highest bits should produce the same result regardless of which kind of shift it is. Thus, your parenthetical remark in the third paragraph of your answer seems a bit misleading.
– Ilmari Karonen
3 hours ago
@Lundin, it is perhaps worthwhile to note that your first set of recommendations assumes thatchunk_lsbandchunk_msbthemselves have type equivalent touint8_t. That isn't clear from the question -- the OP's "8 bits chunks" could be stored in variables having a wider type, or a signed one.
– John Bollinger
3 hours ago
@IlmariKaronen: If the authors of the Standard had required either zero-fill or sign-extension behavior, but there had been some platform where some other behavior would have been more useful, mandating zero-fill or sign-extension behavior could have made C less useful on that platform. The only situations where it should better whether the Standard mandates those two particular behaviors would be if such a platform actually exists, or a compiler writer feels like being deliberately weird. The former case would be best accommodated by not mandating the behavior...
– supercat
2 hours ago
|
show 1 more comment
It isn't clear what type variable is. Without that specified, we can only speculate.
But in general, you should avoid bit shifting on signed integer types, as that leads to various forms of poorly-defined behavior. This in turn means that you have to be careful with small integer types too, because they get promoted to signed int. See Implicit type promotion rules.
The specific case of (uint8)((variable >> 8) & 0xFFu); is safe if variable is unsigned. Otherwise it is unsafe, since right-shifting a negative value leads to implementation-defined behavior (arithmetic or logical shift).
variable << 8 will invoke undefined behavior on 16 bit systems in case variable is a small integer type, or an int16_t.
The safest, most portable way no matter left/right shift is therefore this:
chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);
Though you might want to be overly explicit in order to silence all compiler warnings:
chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );
AFAICT(variable >> 8) & 0xFFuwill give the same result regardless of whether the shift is arithmetic or logical, as long asintis at least 16 bits wide (which I believe the standard guarantees it to be).
– Ilmari Karonen
4 hours ago
1
@IlmariKaronen The size of the variable doesn't matter for that, only the signedness. In case the value is negative, you get implementation-defined behavior. One example of such broken code would beunsigned char u = 0; ... ~u >> n;
– Lundin
4 hours ago
I agree that it's unpredictable, insofar as the standard doesn't require the implementation-defined result of right-shifting a negative signed integer to be either an arithmetic or a logical shift. However, on implementations where it is one of those two, shifting right by n bits and then masking off (at least) the n highest bits should produce the same result regardless of which kind of shift it is. Thus, your parenthetical remark in the third paragraph of your answer seems a bit misleading.
– Ilmari Karonen
3 hours ago
@Lundin, it is perhaps worthwhile to note that your first set of recommendations assumes thatchunk_lsbandchunk_msbthemselves have type equivalent touint8_t. That isn't clear from the question -- the OP's "8 bits chunks" could be stored in variables having a wider type, or a signed one.
– John Bollinger
3 hours ago
@IlmariKaronen: If the authors of the Standard had required either zero-fill or sign-extension behavior, but there had been some platform where some other behavior would have been more useful, mandating zero-fill or sign-extension behavior could have made C less useful on that platform. The only situations where it should better whether the Standard mandates those two particular behaviors would be if such a platform actually exists, or a compiler writer feels like being deliberately weird. The former case would be best accommodated by not mandating the behavior...
– supercat
2 hours ago
|
show 1 more comment
It isn't clear what type variable is. Without that specified, we can only speculate.
But in general, you should avoid bit shifting on signed integer types, as that leads to various forms of poorly-defined behavior. This in turn means that you have to be careful with small integer types too, because they get promoted to signed int. See Implicit type promotion rules.
The specific case of (uint8)((variable >> 8) & 0xFFu); is safe if variable is unsigned. Otherwise it is unsafe, since right-shifting a negative value leads to implementation-defined behavior (arithmetic or logical shift).
variable << 8 will invoke undefined behavior on 16 bit systems in case variable is a small integer type, or an int16_t.
The safest, most portable way no matter left/right shift is therefore this:
chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);
Though you might want to be overly explicit in order to silence all compiler warnings:
chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );
It isn't clear what type variable is. Without that specified, we can only speculate.
But in general, you should avoid bit shifting on signed integer types, as that leads to various forms of poorly-defined behavior. This in turn means that you have to be careful with small integer types too, because they get promoted to signed int. See Implicit type promotion rules.
The specific case of (uint8)((variable >> 8) & 0xFFu); is safe if variable is unsigned. Otherwise it is unsafe, since right-shifting a negative value leads to implementation-defined behavior (arithmetic or logical shift).
variable << 8 will invoke undefined behavior on 16 bit systems in case variable is a small integer type, or an int16_t.
The safest, most portable way no matter left/right shift is therefore this:
chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);
Though you might want to be overly explicit in order to silence all compiler warnings:
chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );
answered 6 hours ago
LundinLundin
110k17161265
110k17161265
AFAICT(variable >> 8) & 0xFFuwill give the same result regardless of whether the shift is arithmetic or logical, as long asintis at least 16 bits wide (which I believe the standard guarantees it to be).
– Ilmari Karonen
4 hours ago
1
@IlmariKaronen The size of the variable doesn't matter for that, only the signedness. In case the value is negative, you get implementation-defined behavior. One example of such broken code would beunsigned char u = 0; ... ~u >> n;
– Lundin
4 hours ago
I agree that it's unpredictable, insofar as the standard doesn't require the implementation-defined result of right-shifting a negative signed integer to be either an arithmetic or a logical shift. However, on implementations where it is one of those two, shifting right by n bits and then masking off (at least) the n highest bits should produce the same result regardless of which kind of shift it is. Thus, your parenthetical remark in the third paragraph of your answer seems a bit misleading.
– Ilmari Karonen
3 hours ago
@Lundin, it is perhaps worthwhile to note that your first set of recommendations assumes thatchunk_lsbandchunk_msbthemselves have type equivalent touint8_t. That isn't clear from the question -- the OP's "8 bits chunks" could be stored in variables having a wider type, or a signed one.
– John Bollinger
3 hours ago
@IlmariKaronen: If the authors of the Standard had required either zero-fill or sign-extension behavior, but there had been some platform where some other behavior would have been more useful, mandating zero-fill or sign-extension behavior could have made C less useful on that platform. The only situations where it should better whether the Standard mandates those two particular behaviors would be if such a platform actually exists, or a compiler writer feels like being deliberately weird. The former case would be best accommodated by not mandating the behavior...
– supercat
2 hours ago
|
show 1 more comment
AFAICT(variable >> 8) & 0xFFuwill give the same result regardless of whether the shift is arithmetic or logical, as long asintis at least 16 bits wide (which I believe the standard guarantees it to be).
– Ilmari Karonen
4 hours ago
1
@IlmariKaronen The size of the variable doesn't matter for that, only the signedness. In case the value is negative, you get implementation-defined behavior. One example of such broken code would beunsigned char u = 0; ... ~u >> n;
– Lundin
4 hours ago
I agree that it's unpredictable, insofar as the standard doesn't require the implementation-defined result of right-shifting a negative signed integer to be either an arithmetic or a logical shift. However, on implementations where it is one of those two, shifting right by n bits and then masking off (at least) the n highest bits should produce the same result regardless of which kind of shift it is. Thus, your parenthetical remark in the third paragraph of your answer seems a bit misleading.
– Ilmari Karonen
3 hours ago
@Lundin, it is perhaps worthwhile to note that your first set of recommendations assumes thatchunk_lsbandchunk_msbthemselves have type equivalent touint8_t. That isn't clear from the question -- the OP's "8 bits chunks" could be stored in variables having a wider type, or a signed one.
– John Bollinger
3 hours ago
@IlmariKaronen: If the authors of the Standard had required either zero-fill or sign-extension behavior, but there had been some platform where some other behavior would have been more useful, mandating zero-fill or sign-extension behavior could have made C less useful on that platform. The only situations where it should better whether the Standard mandates those two particular behaviors would be if such a platform actually exists, or a compiler writer feels like being deliberately weird. The former case would be best accommodated by not mandating the behavior...
– supercat
2 hours ago
AFAICT
(variable >> 8) & 0xFFu will give the same result regardless of whether the shift is arithmetic or logical, as long as int is at least 16 bits wide (which I believe the standard guarantees it to be).– Ilmari Karonen
4 hours ago
AFAICT
(variable >> 8) & 0xFFu will give the same result regardless of whether the shift is arithmetic or logical, as long as int is at least 16 bits wide (which I believe the standard guarantees it to be).– Ilmari Karonen
4 hours ago
1
1
@IlmariKaronen The size of the variable doesn't matter for that, only the signedness. In case the value is negative, you get implementation-defined behavior. One example of such broken code would be
unsigned char u = 0; ... ~u >> n;– Lundin
4 hours ago
@IlmariKaronen The size of the variable doesn't matter for that, only the signedness. In case the value is negative, you get implementation-defined behavior. One example of such broken code would be
unsigned char u = 0; ... ~u >> n;– Lundin
4 hours ago
I agree that it's unpredictable, insofar as the standard doesn't require the implementation-defined result of right-shifting a negative signed integer to be either an arithmetic or a logical shift. However, on implementations where it is one of those two, shifting right by n bits and then masking off (at least) the n highest bits should produce the same result regardless of which kind of shift it is. Thus, your parenthetical remark in the third paragraph of your answer seems a bit misleading.
– Ilmari Karonen
3 hours ago
I agree that it's unpredictable, insofar as the standard doesn't require the implementation-defined result of right-shifting a negative signed integer to be either an arithmetic or a logical shift. However, on implementations where it is one of those two, shifting right by n bits and then masking off (at least) the n highest bits should produce the same result regardless of which kind of shift it is. Thus, your parenthetical remark in the third paragraph of your answer seems a bit misleading.
– Ilmari Karonen
3 hours ago
@Lundin, it is perhaps worthwhile to note that your first set of recommendations assumes that
chunk_lsb and chunk_msb themselves have type equivalent to uint8_t. That isn't clear from the question -- the OP's "8 bits chunks" could be stored in variables having a wider type, or a signed one.– John Bollinger
3 hours ago
@Lundin, it is perhaps worthwhile to note that your first set of recommendations assumes that
chunk_lsb and chunk_msb themselves have type equivalent to uint8_t. That isn't clear from the question -- the OP's "8 bits chunks" could be stored in variables having a wider type, or a signed one.– John Bollinger
3 hours ago
@IlmariKaronen: If the authors of the Standard had required either zero-fill or sign-extension behavior, but there had been some platform where some other behavior would have been more useful, mandating zero-fill or sign-extension behavior could have made C less useful on that platform. The only situations where it should better whether the Standard mandates those two particular behaviors would be if such a platform actually exists, or a compiler writer feels like being deliberately weird. The former case would be best accommodated by not mandating the behavior...
– supercat
2 hours ago
@IlmariKaronen: If the authors of the Standard had required either zero-fill or sign-extension behavior, but there had been some platform where some other behavior would have been more useful, mandating zero-fill or sign-extension behavior could have made C less useful on that platform. The only situations where it should better whether the Standard mandates those two particular behaviors would be if such a platform actually exists, or a compiler writer feels like being deliberately weird. The former case would be best accommodated by not mandating the behavior...
– supercat
2 hours ago
|
show 1 more comment
Since uint8 is unsigned, you don't have to do the masking:
6.3.1.3 Signed and unsigned integers
- When a value with integer type is converted to another integer type other than _ Bool , if the value
can be represented by the new type, it is unchanged.
- Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting
one more than the maximum value that can be represented in the new type until the value is in the
range of the new type. 60)
- Otherwise, the new type is signed and the value cannot be represented in it; either the result is
implementation-defined or an implementation-defined signal is raised.
However, most likely both will result in the same compiler output. I usually add the mask because it makes clear what code is supposed to do, and makes the cast unnecessary.
1
Except, C has nasty integer promotion, so if you try to do the same thing and left shift, the program may implode in undefined behavior. In this particular case we get away since it is right shift of a positive number.
– Lundin
7 hours ago
Also, the cast makes the loss of precision clearly intentional. Many compilers can emit warning on loss of precision, which can extremely important. (I'm thinking of noobs who are so certain that "size_tand pointers are really justunsigned int...)
– Andrew Henle
6 hours ago
@Lundin: Under C89, signed left-shift behavior was defined for all possible left-operand values on implementations whose integer types don't have padding bits or trap representations, but trapping might have been more sensible in situations where the mandated behavior would differ from that of power-of-two multiplication. I've seen no evidence to suggest any intention to change the handling of situations where C89's behavior and power-of-two multiplication would be equivalent.
– supercat
2 hours ago
@supercat It's bad enough to accidentally shift data into the sign bit, regardless of UB and signedness format.
– Lundin
49 mins ago
@Lundin: In two's-complement notation, the sign bit is simply shorthand for "the state of this bit and an infinite number of bits to the left". The value -3 is an infinite number of ones followed by 01. It may be more convenient to think of a 32-bit two's-complement value as being composed of an infinite number of 0's or 1's followed by exactly 31 more bits, but an infinite number of 1's, followed by 29 more, and then 01, is the same as an infinite number of 1's followed by 01.
– supercat
23 mins ago
|
show 1 more comment
Since uint8 is unsigned, you don't have to do the masking:
6.3.1.3 Signed and unsigned integers
- When a value with integer type is converted to another integer type other than _ Bool , if the value
can be represented by the new type, it is unchanged.
- Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting
one more than the maximum value that can be represented in the new type until the value is in the
range of the new type. 60)
- Otherwise, the new type is signed and the value cannot be represented in it; either the result is
implementation-defined or an implementation-defined signal is raised.
However, most likely both will result in the same compiler output. I usually add the mask because it makes clear what code is supposed to do, and makes the cast unnecessary.
1
Except, C has nasty integer promotion, so if you try to do the same thing and left shift, the program may implode in undefined behavior. In this particular case we get away since it is right shift of a positive number.
– Lundin
7 hours ago
Also, the cast makes the loss of precision clearly intentional. Many compilers can emit warning on loss of precision, which can extremely important. (I'm thinking of noobs who are so certain that "size_tand pointers are really justunsigned int...)
– Andrew Henle
6 hours ago
@Lundin: Under C89, signed left-shift behavior was defined for all possible left-operand values on implementations whose integer types don't have padding bits or trap representations, but trapping might have been more sensible in situations where the mandated behavior would differ from that of power-of-two multiplication. I've seen no evidence to suggest any intention to change the handling of situations where C89's behavior and power-of-two multiplication would be equivalent.
– supercat
2 hours ago
@supercat It's bad enough to accidentally shift data into the sign bit, regardless of UB and signedness format.
– Lundin
49 mins ago
@Lundin: In two's-complement notation, the sign bit is simply shorthand for "the state of this bit and an infinite number of bits to the left". The value -3 is an infinite number of ones followed by 01. It may be more convenient to think of a 32-bit two's-complement value as being composed of an infinite number of 0's or 1's followed by exactly 31 more bits, but an infinite number of 1's, followed by 29 more, and then 01, is the same as an infinite number of 1's followed by 01.
– supercat
23 mins ago
|
show 1 more comment
Since uint8 is unsigned, you don't have to do the masking:
6.3.1.3 Signed and unsigned integers
- When a value with integer type is converted to another integer type other than _ Bool , if the value
can be represented by the new type, it is unchanged.
- Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting
one more than the maximum value that can be represented in the new type until the value is in the
range of the new type. 60)
- Otherwise, the new type is signed and the value cannot be represented in it; either the result is
implementation-defined or an implementation-defined signal is raised.
However, most likely both will result in the same compiler output. I usually add the mask because it makes clear what code is supposed to do, and makes the cast unnecessary.
Since uint8 is unsigned, you don't have to do the masking:
6.3.1.3 Signed and unsigned integers
- When a value with integer type is converted to another integer type other than _ Bool , if the value
can be represented by the new type, it is unchanged.
- Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting
one more than the maximum value that can be represented in the new type until the value is in the
range of the new type. 60)
- Otherwise, the new type is signed and the value cannot be represented in it; either the result is
implementation-defined or an implementation-defined signal is raised.
However, most likely both will result in the same compiler output. I usually add the mask because it makes clear what code is supposed to do, and makes the cast unnecessary.
answered 7 hours ago
user694733user694733
11k12850
11k12850
1
Except, C has nasty integer promotion, so if you try to do the same thing and left shift, the program may implode in undefined behavior. In this particular case we get away since it is right shift of a positive number.
– Lundin
7 hours ago
Also, the cast makes the loss of precision clearly intentional. Many compilers can emit warning on loss of precision, which can extremely important. (I'm thinking of noobs who are so certain that "size_tand pointers are really justunsigned int...)
– Andrew Henle
6 hours ago
@Lundin: Under C89, signed left-shift behavior was defined for all possible left-operand values on implementations whose integer types don't have padding bits or trap representations, but trapping might have been more sensible in situations where the mandated behavior would differ from that of power-of-two multiplication. I've seen no evidence to suggest any intention to change the handling of situations where C89's behavior and power-of-two multiplication would be equivalent.
– supercat
2 hours ago
@supercat It's bad enough to accidentally shift data into the sign bit, regardless of UB and signedness format.
– Lundin
49 mins ago
@Lundin: In two's-complement notation, the sign bit is simply shorthand for "the state of this bit and an infinite number of bits to the left". The value -3 is an infinite number of ones followed by 01. It may be more convenient to think of a 32-bit two's-complement value as being composed of an infinite number of 0's or 1's followed by exactly 31 more bits, but an infinite number of 1's, followed by 29 more, and then 01, is the same as an infinite number of 1's followed by 01.
– supercat
23 mins ago
|
show 1 more comment
1
Except, C has nasty integer promotion, so if you try to do the same thing and left shift, the program may implode in undefined behavior. In this particular case we get away since it is right shift of a positive number.
– Lundin
7 hours ago
Also, the cast makes the loss of precision clearly intentional. Many compilers can emit warning on loss of precision, which can extremely important. (I'm thinking of noobs who are so certain that "size_tand pointers are really justunsigned int...)
– Andrew Henle
6 hours ago
@Lundin: Under C89, signed left-shift behavior was defined for all possible left-operand values on implementations whose integer types don't have padding bits or trap representations, but trapping might have been more sensible in situations where the mandated behavior would differ from that of power-of-two multiplication. I've seen no evidence to suggest any intention to change the handling of situations where C89's behavior and power-of-two multiplication would be equivalent.
– supercat
2 hours ago
@supercat It's bad enough to accidentally shift data into the sign bit, regardless of UB and signedness format.
– Lundin
49 mins ago
@Lundin: In two's-complement notation, the sign bit is simply shorthand for "the state of this bit and an infinite number of bits to the left". The value -3 is an infinite number of ones followed by 01. It may be more convenient to think of a 32-bit two's-complement value as being composed of an infinite number of 0's or 1's followed by exactly 31 more bits, but an infinite number of 1's, followed by 29 more, and then 01, is the same as an infinite number of 1's followed by 01.
– supercat
23 mins ago
1
1
Except, C has nasty integer promotion, so if you try to do the same thing and left shift, the program may implode in undefined behavior. In this particular case we get away since it is right shift of a positive number.
– Lundin
7 hours ago
Except, C has nasty integer promotion, so if you try to do the same thing and left shift, the program may implode in undefined behavior. In this particular case we get away since it is right shift of a positive number.
– Lundin
7 hours ago
Also, the cast makes the loss of precision clearly intentional. Many compilers can emit warning on loss of precision, which can extremely important. (I'm thinking of noobs who are so certain that "
size_t and pointers are really just unsigned int...)– Andrew Henle
6 hours ago
Also, the cast makes the loss of precision clearly intentional. Many compilers can emit warning on loss of precision, which can extremely important. (I'm thinking of noobs who are so certain that "
size_t and pointers are really just unsigned int...)– Andrew Henle
6 hours ago
@Lundin: Under C89, signed left-shift behavior was defined for all possible left-operand values on implementations whose integer types don't have padding bits or trap representations, but trapping might have been more sensible in situations where the mandated behavior would differ from that of power-of-two multiplication. I've seen no evidence to suggest any intention to change the handling of situations where C89's behavior and power-of-two multiplication would be equivalent.
– supercat
2 hours ago
@Lundin: Under C89, signed left-shift behavior was defined for all possible left-operand values on implementations whose integer types don't have padding bits or trap representations, but trapping might have been more sensible in situations where the mandated behavior would differ from that of power-of-two multiplication. I've seen no evidence to suggest any intention to change the handling of situations where C89's behavior and power-of-two multiplication would be equivalent.
– supercat
2 hours ago
@supercat It's bad enough to accidentally shift data into the sign bit, regardless of UB and signedness format.
– Lundin
49 mins ago
@supercat It's bad enough to accidentally shift data into the sign bit, regardless of UB and signedness format.
– Lundin
49 mins ago
@Lundin: In two's-complement notation, the sign bit is simply shorthand for "the state of this bit and an infinite number of bits to the left". The value -3 is an infinite number of ones followed by 01. It may be more convenient to think of a 32-bit two's-complement value as being composed of an infinite number of 0's or 1's followed by exactly 31 more bits, but an infinite number of 1's, followed by 29 more, and then 01, is the same as an infinite number of 1's followed by 01.
– supercat
23 mins ago
@Lundin: In two's-complement notation, the sign bit is simply shorthand for "the state of this bit and an infinite number of bits to the left". The value -3 is an infinite number of ones followed by 01. It may be more convenient to think of a 32-bit two's-complement value as being composed of an infinite number of 0's or 1's followed by exactly 31 more bits, but an infinite number of 1's, followed by 29 more, and then 01, is the same as an infinite number of 1's followed by 01.
– supercat
23 mins ago
|
show 1 more comment
Should a cast be used to truncate a long variable?
If chunk_lsb is an 8 bit object (narrower than variable), use cast or mask (not both). Useful in quieting pedantic warnings about range reduction. I prefer the mask - unless the compiler is picky.
uint8_t chunk_lsb = (uint8_t) variable;
// or
uint8_t chunk_lsb = variable & 0xFFu;
Otherwise use the mask.
unsigned chunk_lsb = variable & 0xFFu;
add a comment |
Should a cast be used to truncate a long variable?
If chunk_lsb is an 8 bit object (narrower than variable), use cast or mask (not both). Useful in quieting pedantic warnings about range reduction. I prefer the mask - unless the compiler is picky.
uint8_t chunk_lsb = (uint8_t) variable;
// or
uint8_t chunk_lsb = variable & 0xFFu;
Otherwise use the mask.
unsigned chunk_lsb = variable & 0xFFu;
add a comment |
Should a cast be used to truncate a long variable?
If chunk_lsb is an 8 bit object (narrower than variable), use cast or mask (not both). Useful in quieting pedantic warnings about range reduction. I prefer the mask - unless the compiler is picky.
uint8_t chunk_lsb = (uint8_t) variable;
// or
uint8_t chunk_lsb = variable & 0xFFu;
Otherwise use the mask.
unsigned chunk_lsb = variable & 0xFFu;
Should a cast be used to truncate a long variable?
If chunk_lsb is an 8 bit object (narrower than variable), use cast or mask (not both). Useful in quieting pedantic warnings about range reduction. I prefer the mask - unless the compiler is picky.
uint8_t chunk_lsb = (uint8_t) variable;
// or
uint8_t chunk_lsb = variable & 0xFFu;
Otherwise use the mask.
unsigned chunk_lsb = variable & 0xFFu;
edited 4 hours ago
answered 6 hours ago
chuxchux
83.2k872151
83.2k872151
add a comment |
add a comment |
Maybe there's none and just use the cast to reduce calculations is the best way?
General speaking, the asm code will be the same, so in terms of speed, it does not matter which one you use:
- masking: https://godbolt.org/z/Olrw3x
- casting: https://godbolt.org/z/EEdvQZ
What do you guys think?
IMO, the first one is clearer, in terms of readability, but I cannot figure out a coding standard or guideline which supports my preference. Anyway, I would use a const variable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking (assuming that you have chosen a correct name for the const variable).
3
Anyway, I would use aconstvariable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking Anyone who thinks0xFFin the context of bit masking is a "magic number" that has to be papered over with a variable is engaging in cargo-cult programming. What possible variable can be more clear than0xFFas a bit mask?one_byte_bit_mask_0xFF?
– Andrew Henle
7 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number.
– Jose
6 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number Oh? How many bits does this mask:unsigned int result = input & mask;And no, I didn't DV.
– Andrew Henle
6 hours ago
0xFFvsone_byte_bit_mask_0xFFvsmask, I choose the second one as the least-bad option.
– Jose
6 hours ago
add a comment |
Maybe there's none and just use the cast to reduce calculations is the best way?
General speaking, the asm code will be the same, so in terms of speed, it does not matter which one you use:
- masking: https://godbolt.org/z/Olrw3x
- casting: https://godbolt.org/z/EEdvQZ
What do you guys think?
IMO, the first one is clearer, in terms of readability, but I cannot figure out a coding standard or guideline which supports my preference. Anyway, I would use a const variable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking (assuming that you have chosen a correct name for the const variable).
3
Anyway, I would use aconstvariable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking Anyone who thinks0xFFin the context of bit masking is a "magic number" that has to be papered over with a variable is engaging in cargo-cult programming. What possible variable can be more clear than0xFFas a bit mask?one_byte_bit_mask_0xFF?
– Andrew Henle
7 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number.
– Jose
6 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number Oh? How many bits does this mask:unsigned int result = input & mask;And no, I didn't DV.
– Andrew Henle
6 hours ago
0xFFvsone_byte_bit_mask_0xFFvsmask, I choose the second one as the least-bad option.
– Jose
6 hours ago
add a comment |
Maybe there's none and just use the cast to reduce calculations is the best way?
General speaking, the asm code will be the same, so in terms of speed, it does not matter which one you use:
- masking: https://godbolt.org/z/Olrw3x
- casting: https://godbolt.org/z/EEdvQZ
What do you guys think?
IMO, the first one is clearer, in terms of readability, but I cannot figure out a coding standard or guideline which supports my preference. Anyway, I would use a const variable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking (assuming that you have chosen a correct name for the const variable).
Maybe there's none and just use the cast to reduce calculations is the best way?
General speaking, the asm code will be the same, so in terms of speed, it does not matter which one you use:
- masking: https://godbolt.org/z/Olrw3x
- casting: https://godbolt.org/z/EEdvQZ
What do you guys think?
IMO, the first one is clearer, in terms of readability, but I cannot figure out a coding standard or guideline which supports my preference. Anyway, I would use a const variable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking (assuming that you have chosen a correct name for the const variable).
answered 7 hours ago
JoseJose
1,241415
1,241415
3
Anyway, I would use aconstvariable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking Anyone who thinks0xFFin the context of bit masking is a "magic number" that has to be papered over with a variable is engaging in cargo-cult programming. What possible variable can be more clear than0xFFas a bit mask?one_byte_bit_mask_0xFF?
– Andrew Henle
7 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number.
– Jose
6 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number Oh? How many bits does this mask:unsigned int result = input & mask;And no, I didn't DV.
– Andrew Henle
6 hours ago
0xFFvsone_byte_bit_mask_0xFFvsmask, I choose the second one as the least-bad option.
– Jose
6 hours ago
add a comment |
3
Anyway, I would use aconstvariable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking Anyone who thinks0xFFin the context of bit masking is a "magic number" that has to be papered over with a variable is engaging in cargo-cult programming. What possible variable can be more clear than0xFFas a bit mask?one_byte_bit_mask_0xFF?
– Andrew Henle
7 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number.
– Jose
6 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number Oh? How many bits does this mask:unsigned int result = input & mask;And no, I didn't DV.
– Andrew Henle
6 hours ago
0xFFvsone_byte_bit_mask_0xFFvsmask, I choose the second one as the least-bad option.
– Jose
6 hours ago
3
3
Anyway, I would use a
const variable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking Anyone who thinks 0xFF in the context of bit masking is a "magic number" that has to be papered over with a variable is engaging in cargo-cult programming. What possible variable can be more clear than 0xFF as a bit mask? one_byte_bit_mask_0xFF?– Andrew Henle
7 hours ago
Anyway, I would use a
const variable if your preference is the second one, to remove magic numbers and make clearer that the purpose is masking Anyone who thinks 0xFF in the context of bit masking is a "magic number" that has to be papered over with a variable is engaging in cargo-cult programming. What possible variable can be more clear than 0xFF as a bit mask? one_byte_bit_mask_0xFF?– Andrew Henle
7 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number.
– Jose
6 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number.
– Jose
6 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number Oh? How many bits does this mask:
unsigned int result = input & mask; And no, I didn't DV.– Andrew Henle
6 hours ago
IMO, if the purpose is to mask, the word mask is clearer than any (magic) number Oh? How many bits does this mask:
unsigned int result = input & mask; And no, I didn't DV.– Andrew Henle
6 hours ago
0xFF vs one_byte_bit_mask_0xFF vs mask, I choose the second one as the least-bad option.– Jose
6 hours ago
0xFF vs one_byte_bit_mask_0xFF vs mask, I choose the second one as the least-bad option.– Jose
6 hours ago
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54866461%2fshould-a-cast-be-used-to-truncate-a-long-variable%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I think both will generate same binary code. As the first solution is more readable, I would use this one. You just need to be sure that uint8 is 8-but on all platforms (i guess it is)
– jaudo
7 hours ago
Thank you @jaudo, that's also the direction I'm taking.
– Soyding Mete
7 hours ago
11
Sidenote: Standard
stdint.htypes such asuint8_tshould be preferred instead of creating your own.– user694733
7 hours ago