left shift count >= width of type in C macro
I have written a C Macro to set/unset Bits in a uint32 variable. Here are the definitions of the macros:
extern uint32_t error_field, error_field2;
#define SET_ERROR_BIT(x) do{
if(x < 0 || x >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ((uint32_t)x)));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<(((uint32_t)x)-32U)));
}
}while(0)
#define RESET_ERROR_BIT(x) do{
if(((uint32_t)x)<32U){
(error_field &= ~((uint32_t)1U<<((uint32_t)x)));
break;
} else if(((uint32_t)x) < 64U){
(error_field2 &= ~((uint32_t)1U<<(((uint32_t)x)-32U)));
}
} while(0)
I am passing a field of an enumeration, that looks like this:
enum error_bits {
error_chamber01_data = 0,
error_port21_data,
error_port22_data,
error_port23_data,
error_port24_data,
/*this goes on until 47*/
};
This warning is produced:
left shift count >= width of type [-Wshift-count-overflow]
I am calling the Macros like this:
USART2->CR1 |= USART_CR1_RXNEIE;
SET_ERROR_BIT(error_usart2);
/*error_usart2 is 47 in the enum*/
return -1;
I get this warning with every macro, even with those where the left shift count is < 31.
If I use the definition of the macro without the macro, it produces no warning. The behaviour is the same with a 64 bit variable. I am programming a STM32F7 with AC6 STM32 MCU GCC compiler.
I can't figure out why this happens. Can anyone help me?
c gcc macros stm32
|
show 10 more comments
I have written a C Macro to set/unset Bits in a uint32 variable. Here are the definitions of the macros:
extern uint32_t error_field, error_field2;
#define SET_ERROR_BIT(x) do{
if(x < 0 || x >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ((uint32_t)x)));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<(((uint32_t)x)-32U)));
}
}while(0)
#define RESET_ERROR_BIT(x) do{
if(((uint32_t)x)<32U){
(error_field &= ~((uint32_t)1U<<((uint32_t)x)));
break;
} else if(((uint32_t)x) < 64U){
(error_field2 &= ~((uint32_t)1U<<(((uint32_t)x)-32U)));
}
} while(0)
I am passing a field of an enumeration, that looks like this:
enum error_bits {
error_chamber01_data = 0,
error_port21_data,
error_port22_data,
error_port23_data,
error_port24_data,
/*this goes on until 47*/
};
This warning is produced:
left shift count >= width of type [-Wshift-count-overflow]
I am calling the Macros like this:
USART2->CR1 |= USART_CR1_RXNEIE;
SET_ERROR_BIT(error_usart2);
/*error_usart2 is 47 in the enum*/
return -1;
I get this warning with every macro, even with those where the left shift count is < 31.
If I use the definition of the macro without the macro, it produces no warning. The behaviour is the same with a 64 bit variable. I am programming a STM32F7 with AC6 STM32 MCU GCC compiler.
I can't figure out why this happens. Can anyone help me?
c gcc macros stm32
1
show where the macro is called also
– LoPiTaL
Nov 26 '18 at 11:06
I have edited the post.
– Vincent Fartmann
Nov 26 '18 at 11:09
1
This (and I really don't mean to cause offence here) truly hideous beast is a classic example of why macros are a bad idea for anything other than simple true/false things in modern C compilers. You could write something far more readable with a function that generally has little performance impact, if any. I always try to optimise for readabilty first :-)
– paxdiablo
Nov 26 '18 at 11:09
I already thought of writing a function for this, but i want to figure out why the warning is produced
– Vincent Fartmann
Nov 26 '18 at 11:12
4
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these disgnostics are issued before the dead branch is eliminated.)
– M Oehm
Nov 26 '18 at 11:16
|
show 10 more comments
I have written a C Macro to set/unset Bits in a uint32 variable. Here are the definitions of the macros:
extern uint32_t error_field, error_field2;
#define SET_ERROR_BIT(x) do{
if(x < 0 || x >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ((uint32_t)x)));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<(((uint32_t)x)-32U)));
}
}while(0)
#define RESET_ERROR_BIT(x) do{
if(((uint32_t)x)<32U){
(error_field &= ~((uint32_t)1U<<((uint32_t)x)));
break;
} else if(((uint32_t)x) < 64U){
(error_field2 &= ~((uint32_t)1U<<(((uint32_t)x)-32U)));
}
} while(0)
I am passing a field of an enumeration, that looks like this:
enum error_bits {
error_chamber01_data = 0,
error_port21_data,
error_port22_data,
error_port23_data,
error_port24_data,
/*this goes on until 47*/
};
This warning is produced:
left shift count >= width of type [-Wshift-count-overflow]
I am calling the Macros like this:
USART2->CR1 |= USART_CR1_RXNEIE;
SET_ERROR_BIT(error_usart2);
/*error_usart2 is 47 in the enum*/
return -1;
I get this warning with every macro, even with those where the left shift count is < 31.
If I use the definition of the macro without the macro, it produces no warning. The behaviour is the same with a 64 bit variable. I am programming a STM32F7 with AC6 STM32 MCU GCC compiler.
I can't figure out why this happens. Can anyone help me?
c gcc macros stm32
I have written a C Macro to set/unset Bits in a uint32 variable. Here are the definitions of the macros:
extern uint32_t error_field, error_field2;
#define SET_ERROR_BIT(x) do{
if(x < 0 || x >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ((uint32_t)x)));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<(((uint32_t)x)-32U)));
}
}while(0)
#define RESET_ERROR_BIT(x) do{
if(((uint32_t)x)<32U){
(error_field &= ~((uint32_t)1U<<((uint32_t)x)));
break;
} else if(((uint32_t)x) < 64U){
(error_field2 &= ~((uint32_t)1U<<(((uint32_t)x)-32U)));
}
} while(0)
I am passing a field of an enumeration, that looks like this:
enum error_bits {
error_chamber01_data = 0,
error_port21_data,
error_port22_data,
error_port23_data,
error_port24_data,
/*this goes on until 47*/
};
This warning is produced:
left shift count >= width of type [-Wshift-count-overflow]
I am calling the Macros like this:
USART2->CR1 |= USART_CR1_RXNEIE;
SET_ERROR_BIT(error_usart2);
/*error_usart2 is 47 in the enum*/
return -1;
I get this warning with every macro, even with those where the left shift count is < 31.
If I use the definition of the macro without the macro, it produces no warning. The behaviour is the same with a 64 bit variable. I am programming a STM32F7 with AC6 STM32 MCU GCC compiler.
I can't figure out why this happens. Can anyone help me?
c gcc macros stm32
c gcc macros stm32
edited Nov 26 '18 at 11:10
Vincent Fartmann
asked Nov 26 '18 at 11:03
Vincent FartmannVincent Fartmann
164
164
1
show where the macro is called also
– LoPiTaL
Nov 26 '18 at 11:06
I have edited the post.
– Vincent Fartmann
Nov 26 '18 at 11:09
1
This (and I really don't mean to cause offence here) truly hideous beast is a classic example of why macros are a bad idea for anything other than simple true/false things in modern C compilers. You could write something far more readable with a function that generally has little performance impact, if any. I always try to optimise for readabilty first :-)
– paxdiablo
Nov 26 '18 at 11:09
I already thought of writing a function for this, but i want to figure out why the warning is produced
– Vincent Fartmann
Nov 26 '18 at 11:12
4
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these disgnostics are issued before the dead branch is eliminated.)
– M Oehm
Nov 26 '18 at 11:16
|
show 10 more comments
1
show where the macro is called also
– LoPiTaL
Nov 26 '18 at 11:06
I have edited the post.
– Vincent Fartmann
Nov 26 '18 at 11:09
1
This (and I really don't mean to cause offence here) truly hideous beast is a classic example of why macros are a bad idea for anything other than simple true/false things in modern C compilers. You could write something far more readable with a function that generally has little performance impact, if any. I always try to optimise for readabilty first :-)
– paxdiablo
Nov 26 '18 at 11:09
I already thought of writing a function for this, but i want to figure out why the warning is produced
– Vincent Fartmann
Nov 26 '18 at 11:12
4
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these disgnostics are issued before the dead branch is eliminated.)
– M Oehm
Nov 26 '18 at 11:16
1
1
show where the macro is called also
– LoPiTaL
Nov 26 '18 at 11:06
show where the macro is called also
– LoPiTaL
Nov 26 '18 at 11:06
I have edited the post.
– Vincent Fartmann
Nov 26 '18 at 11:09
I have edited the post.
– Vincent Fartmann
Nov 26 '18 at 11:09
1
1
This (and I really don't mean to cause offence here) truly hideous beast is a classic example of why macros are a bad idea for anything other than simple true/false things in modern C compilers. You could write something far more readable with a function that generally has little performance impact, if any. I always try to optimise for readabilty first :-)
– paxdiablo
Nov 26 '18 at 11:09
This (and I really don't mean to cause offence here) truly hideous beast is a classic example of why macros are a bad idea for anything other than simple true/false things in modern C compilers. You could write something far more readable with a function that generally has little performance impact, if any. I always try to optimise for readabilty first :-)
– paxdiablo
Nov 26 '18 at 11:09
I already thought of writing a function for this, but i want to figure out why the warning is produced
– Vincent Fartmann
Nov 26 '18 at 11:12
I already thought of writing a function for this, but i want to figure out why the warning is produced
– Vincent Fartmann
Nov 26 '18 at 11:12
4
4
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these disgnostics are issued before the dead branch is eliminated.)
– M Oehm
Nov 26 '18 at 11:16
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these disgnostics are issued before the dead branch is eliminated.)
– M Oehm
Nov 26 '18 at 11:16
|
show 10 more comments
3 Answers
3
active
oldest
votes
Probably a problem with the compiler not being able to diagnose correctly, as stated by M Oehm. A workaround could be, instead of using the minus operation, use the remainder operation:
#define _SET_BIT(x, bit) (x) |= 1U<<((bit) % 32U)
#define SET_BIT(x, bit) _SET_BIT(x, (uint32_t)(bit))
#define _SET_ERROR_BIT(x) do{
if((x)<32U){
SET_BIT(error_field, x);
} else if((x)<64U){
SET_BIT(error_field2, x);
}
}while(0)
#define SET_ERROR_BIT(x) _SET_ERROR_BIT((uint32_t)(x))
This way the compiler is finally smart enough to know that the value of x will never exceed 32.
The call to the "_" macro is used in order to force x to always be an uint32_t, inconditionally of the macro call, avoiding the UB of a call with a negative value of x.
Tested in coliru
This works fine for numbers <32. For numbers >=32 it produces the same warning: coliru.stacked-crooked.com/a/3d79a452e4a6efda
– Vincent Fartmann
Nov 26 '18 at 11:32
yes, because the other branch needs also the modulus operation, I update the link
– LoPiTaL
Nov 26 '18 at 11:34
I have also simplified the macro, removing unnecessary castings and breaks
– LoPiTaL
Nov 26 '18 at 11:39
I figured out the fault, see the last comment. Thank you!
– Vincent Fartmann
Nov 26 '18 at 11:39
1
Yes, with -1LL that is true, did not see that. Still hole remains, but in a new, and less likely, place such as SET_ERROR_BIT(-0x100000000) as the(uint32_t)cast simply wraps the negative values and then some will end up as 0-63.
– chux
Nov 26 '18 at 14:57
|
show 6 more comments
Problem:
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these diagnostics are issued before the dead branch is eliminated.)
@M Oehm
Solution
Insure shifts are in range 0-31 in both paths regardless of the x value and type of x.
x & 31 is a stronger insurance than x%32 or x%32u. % can result in negative remainders when x < 0 and with a wide enough type.
#define SET_ERROR_BIT(x) do{
if((x) < 0 || (x) >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ( (x)&31 )));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<( (x)&31 )));
}
}while(0)
As a general rule: good to use () around each usage of x.
add a comment |
Seeing the thread I wanted to indicate a nice (and perhaps cleaner) way to set, reset and toggle the status of a bit in the case of the two unsigned integers as in thread. This code should be OT because uses x that shall be an unsigned int (or an int) and not a enum value.
I've written the line of code at the end of this answer.
The code receives as input a number of parameter couples. Each couple of parameter is a letter and a number. The letter may be:
- S to set a bit
- R to reset a bit
- T to toggle a bit
The number has to be a bit value from 0 to 63. The macros in the code discard each number greater than 63 and nothing is modified into the variables. The negative values haven't been evalued because we suppose a bit value is an unsigned value.
For Example (if we name the program bitman):
Executing: bitman S 0 S 1 T 7 S 64 T 7 S 2 T 80 R 1 S 63 S 32 R 63 T 62
The output will be:
S 0 00000000-00000001
S 1 00000000-00000003
T 7 00000000-00000083
S 64 00000000-00000083
T 7 00000000-00000003
S 2 00000000-00000007
T 80 00000000-00000007
R 1 00000000-00000005
S 63 80000000-00000005
S 32 80000001-00000005
R 63 00000001-00000005
T 62 40000001-00000005
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint32_t err1 = 0;
static uint32_t err2 = 0;
#define SET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 |= (1U<<(x))):
(err2 |= (1U<<((x)-32)))
)
#define RESET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 &= ~(1U<<(x))):
(err2 &= ~(1U<<((x)-32)))
)
#define TOGGLE_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 ^= (1U<<(x))):
(err2 ^= (1U<<((x)-32)))
)
int main(int argc, char *argv)
{
int i;
unsigned int x;
for(i=1;i<argc;i+=2) {
x=strtoul(argv[i+1],NULL,0);
switch (argv[i][0]) {
case 'S':
SET_ERROR_BIT(x);
break;
case 'T':
TOGGLE_ERROR_BIT(x);
break;
case 'R':
RESET_ERROR_BIT(x);
break;
default:
break;
}
printf("%c %2d %08X-%08Xn",argv[i][0], x, err2, err1);
}
return 0;
}
The macros are splitted in more then one line, but they are each a one-line code.
The code main has no error control then if the parameters are not correctly specified the program might be undefined behaviour.
OP's code handledx < 0. This answer, like first one, has vulnerability whenx < 0.
– chux
Nov 26 '18 at 13:32
It's not a vulnerability to avoid the x<0 control, because the input variable should be considered an unsigned at compilation time. If you use an int the code will be compiled with error. If you force the variable at a negative value the code will consider the value as a number greater or equal to 0, so it is sufficient to consider the control on greater than 63.
– Sir Jo Black
Nov 26 '18 at 13:37
1
Disagree with "because the input variable should be considered an unsigned at compilation time". Enumerated values are not certainly unsigned ref and OP wisely wants to prevent possibility withif(x < 0
– chux
Nov 26 '18 at 13:42
In the code I've implemented the variable x is an unsigned. May be I'm OT.
– Sir Jo Black
Nov 26 '18 at 13:46
@Chux, I understood your point of view :)
– Sir Jo Black
Nov 26 '18 at 13:50
add a comment |
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%2f53479744%2fleft-shift-count-width-of-type-in-c-macro%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Probably a problem with the compiler not being able to diagnose correctly, as stated by M Oehm. A workaround could be, instead of using the minus operation, use the remainder operation:
#define _SET_BIT(x, bit) (x) |= 1U<<((bit) % 32U)
#define SET_BIT(x, bit) _SET_BIT(x, (uint32_t)(bit))
#define _SET_ERROR_BIT(x) do{
if((x)<32U){
SET_BIT(error_field, x);
} else if((x)<64U){
SET_BIT(error_field2, x);
}
}while(0)
#define SET_ERROR_BIT(x) _SET_ERROR_BIT((uint32_t)(x))
This way the compiler is finally smart enough to know that the value of x will never exceed 32.
The call to the "_" macro is used in order to force x to always be an uint32_t, inconditionally of the macro call, avoiding the UB of a call with a negative value of x.
Tested in coliru
This works fine for numbers <32. For numbers >=32 it produces the same warning: coliru.stacked-crooked.com/a/3d79a452e4a6efda
– Vincent Fartmann
Nov 26 '18 at 11:32
yes, because the other branch needs also the modulus operation, I update the link
– LoPiTaL
Nov 26 '18 at 11:34
I have also simplified the macro, removing unnecessary castings and breaks
– LoPiTaL
Nov 26 '18 at 11:39
I figured out the fault, see the last comment. Thank you!
– Vincent Fartmann
Nov 26 '18 at 11:39
1
Yes, with -1LL that is true, did not see that. Still hole remains, but in a new, and less likely, place such as SET_ERROR_BIT(-0x100000000) as the(uint32_t)cast simply wraps the negative values and then some will end up as 0-63.
– chux
Nov 26 '18 at 14:57
|
show 6 more comments
Probably a problem with the compiler not being able to diagnose correctly, as stated by M Oehm. A workaround could be, instead of using the minus operation, use the remainder operation:
#define _SET_BIT(x, bit) (x) |= 1U<<((bit) % 32U)
#define SET_BIT(x, bit) _SET_BIT(x, (uint32_t)(bit))
#define _SET_ERROR_BIT(x) do{
if((x)<32U){
SET_BIT(error_field, x);
} else if((x)<64U){
SET_BIT(error_field2, x);
}
}while(0)
#define SET_ERROR_BIT(x) _SET_ERROR_BIT((uint32_t)(x))
This way the compiler is finally smart enough to know that the value of x will never exceed 32.
The call to the "_" macro is used in order to force x to always be an uint32_t, inconditionally of the macro call, avoiding the UB of a call with a negative value of x.
Tested in coliru
This works fine for numbers <32. For numbers >=32 it produces the same warning: coliru.stacked-crooked.com/a/3d79a452e4a6efda
– Vincent Fartmann
Nov 26 '18 at 11:32
yes, because the other branch needs also the modulus operation, I update the link
– LoPiTaL
Nov 26 '18 at 11:34
I have also simplified the macro, removing unnecessary castings and breaks
– LoPiTaL
Nov 26 '18 at 11:39
I figured out the fault, see the last comment. Thank you!
– Vincent Fartmann
Nov 26 '18 at 11:39
1
Yes, with -1LL that is true, did not see that. Still hole remains, but in a new, and less likely, place such as SET_ERROR_BIT(-0x100000000) as the(uint32_t)cast simply wraps the negative values and then some will end up as 0-63.
– chux
Nov 26 '18 at 14:57
|
show 6 more comments
Probably a problem with the compiler not being able to diagnose correctly, as stated by M Oehm. A workaround could be, instead of using the minus operation, use the remainder operation:
#define _SET_BIT(x, bit) (x) |= 1U<<((bit) % 32U)
#define SET_BIT(x, bit) _SET_BIT(x, (uint32_t)(bit))
#define _SET_ERROR_BIT(x) do{
if((x)<32U){
SET_BIT(error_field, x);
} else if((x)<64U){
SET_BIT(error_field2, x);
}
}while(0)
#define SET_ERROR_BIT(x) _SET_ERROR_BIT((uint32_t)(x))
This way the compiler is finally smart enough to know that the value of x will never exceed 32.
The call to the "_" macro is used in order to force x to always be an uint32_t, inconditionally of the macro call, avoiding the UB of a call with a negative value of x.
Tested in coliru
Probably a problem with the compiler not being able to diagnose correctly, as stated by M Oehm. A workaround could be, instead of using the minus operation, use the remainder operation:
#define _SET_BIT(x, bit) (x) |= 1U<<((bit) % 32U)
#define SET_BIT(x, bit) _SET_BIT(x, (uint32_t)(bit))
#define _SET_ERROR_BIT(x) do{
if((x)<32U){
SET_BIT(error_field, x);
} else if((x)<64U){
SET_BIT(error_field2, x);
}
}while(0)
#define SET_ERROR_BIT(x) _SET_ERROR_BIT((uint32_t)(x))
This way the compiler is finally smart enough to know that the value of x will never exceed 32.
The call to the "_" macro is used in order to force x to always be an uint32_t, inconditionally of the macro call, avoiding the UB of a call with a negative value of x.
Tested in coliru
edited Nov 26 '18 at 14:05
answered Nov 26 '18 at 11:23
LoPiTaLLoPiTaL
1,819914
1,819914
This works fine for numbers <32. For numbers >=32 it produces the same warning: coliru.stacked-crooked.com/a/3d79a452e4a6efda
– Vincent Fartmann
Nov 26 '18 at 11:32
yes, because the other branch needs also the modulus operation, I update the link
– LoPiTaL
Nov 26 '18 at 11:34
I have also simplified the macro, removing unnecessary castings and breaks
– LoPiTaL
Nov 26 '18 at 11:39
I figured out the fault, see the last comment. Thank you!
– Vincent Fartmann
Nov 26 '18 at 11:39
1
Yes, with -1LL that is true, did not see that. Still hole remains, but in a new, and less likely, place such as SET_ERROR_BIT(-0x100000000) as the(uint32_t)cast simply wraps the negative values and then some will end up as 0-63.
– chux
Nov 26 '18 at 14:57
|
show 6 more comments
This works fine for numbers <32. For numbers >=32 it produces the same warning: coliru.stacked-crooked.com/a/3d79a452e4a6efda
– Vincent Fartmann
Nov 26 '18 at 11:32
yes, because the other branch needs also the modulus operation, I update the link
– LoPiTaL
Nov 26 '18 at 11:34
I have also simplified the macro, removing unnecessary castings and breaks
– LoPiTaL
Nov 26 '18 at 11:39
I figured out the fault, see the last comment. Thank you!
– Vincent Fartmann
Nov 26 '18 at 11:39
1
Yes, with -1LL that is true, did not see that. Still hole remains, but in a new, and less likely, place such as SET_ERROR_BIT(-0x100000000) as the(uint32_t)cast simply wraps the negative values and then some will end up as 0-63.
– chux
Nov 26 '18 at 14:57
This works fine for numbers <32. For numbers >=32 it produces the same warning: coliru.stacked-crooked.com/a/3d79a452e4a6efda
– Vincent Fartmann
Nov 26 '18 at 11:32
This works fine for numbers <32. For numbers >=32 it produces the same warning: coliru.stacked-crooked.com/a/3d79a452e4a6efda
– Vincent Fartmann
Nov 26 '18 at 11:32
yes, because the other branch needs also the modulus operation, I update the link
– LoPiTaL
Nov 26 '18 at 11:34
yes, because the other branch needs also the modulus operation, I update the link
– LoPiTaL
Nov 26 '18 at 11:34
I have also simplified the macro, removing unnecessary castings and breaks
– LoPiTaL
Nov 26 '18 at 11:39
I have also simplified the macro, removing unnecessary castings and breaks
– LoPiTaL
Nov 26 '18 at 11:39
I figured out the fault, see the last comment. Thank you!
– Vincent Fartmann
Nov 26 '18 at 11:39
I figured out the fault, see the last comment. Thank you!
– Vincent Fartmann
Nov 26 '18 at 11:39
1
1
Yes, with -1LL that is true, did not see that. Still hole remains, but in a new, and less likely, place such as SET_ERROR_BIT(-0x100000000) as the
(uint32_t) cast simply wraps the negative values and then some will end up as 0-63.– chux
Nov 26 '18 at 14:57
Yes, with -1LL that is true, did not see that. Still hole remains, but in a new, and less likely, place such as SET_ERROR_BIT(-0x100000000) as the
(uint32_t) cast simply wraps the negative values and then some will end up as 0-63.– chux
Nov 26 '18 at 14:57
|
show 6 more comments
Problem:
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these diagnostics are issued before the dead branch is eliminated.)
@M Oehm
Solution
Insure shifts are in range 0-31 in both paths regardless of the x value and type of x.
x & 31 is a stronger insurance than x%32 or x%32u. % can result in negative remainders when x < 0 and with a wide enough type.
#define SET_ERROR_BIT(x) do{
if((x) < 0 || (x) >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ( (x)&31 )));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<( (x)&31 )));
}
}while(0)
As a general rule: good to use () around each usage of x.
add a comment |
Problem:
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these diagnostics are issued before the dead branch is eliminated.)
@M Oehm
Solution
Insure shifts are in range 0-31 in both paths regardless of the x value and type of x.
x & 31 is a stronger insurance than x%32 or x%32u. % can result in negative remainders when x < 0 and with a wide enough type.
#define SET_ERROR_BIT(x) do{
if((x) < 0 || (x) >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ( (x)&31 )));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<( (x)&31 )));
}
}while(0)
As a general rule: good to use () around each usage of x.
add a comment |
Problem:
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these diagnostics are issued before the dead branch is eliminated.)
@M Oehm
Solution
Insure shifts are in range 0-31 in both paths regardless of the x value and type of x.
x & 31 is a stronger insurance than x%32 or x%32u. % can result in negative remainders when x < 0 and with a wide enough type.
#define SET_ERROR_BIT(x) do{
if((x) < 0 || (x) >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ( (x)&31 )));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<( (x)&31 )));
}
}while(0)
As a general rule: good to use () around each usage of x.
Problem:
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these diagnostics are issued before the dead branch is eliminated.)
@M Oehm
Solution
Insure shifts are in range 0-31 in both paths regardless of the x value and type of x.
x & 31 is a stronger insurance than x%32 or x%32u. % can result in negative remainders when x < 0 and with a wide enough type.
#define SET_ERROR_BIT(x) do{
if((x) < 0 || (x) >63){
break;
}
if(((uint32_t)x)<32U){
(error_field |= ((uint32_t)1U << ( (x)&31 )));
break;
} else if(((uint32_t)x)<64U){
(error_field2 |= ((uint32_t)1U<<( (x)&31 )));
}
}while(0)
As a general rule: good to use () around each usage of x.
edited Nov 26 '18 at 14:18
answered Nov 26 '18 at 13:47
chuxchux
84.8k874157
84.8k874157
add a comment |
add a comment |
Seeing the thread I wanted to indicate a nice (and perhaps cleaner) way to set, reset and toggle the status of a bit in the case of the two unsigned integers as in thread. This code should be OT because uses x that shall be an unsigned int (or an int) and not a enum value.
I've written the line of code at the end of this answer.
The code receives as input a number of parameter couples. Each couple of parameter is a letter and a number. The letter may be:
- S to set a bit
- R to reset a bit
- T to toggle a bit
The number has to be a bit value from 0 to 63. The macros in the code discard each number greater than 63 and nothing is modified into the variables. The negative values haven't been evalued because we suppose a bit value is an unsigned value.
For Example (if we name the program bitman):
Executing: bitman S 0 S 1 T 7 S 64 T 7 S 2 T 80 R 1 S 63 S 32 R 63 T 62
The output will be:
S 0 00000000-00000001
S 1 00000000-00000003
T 7 00000000-00000083
S 64 00000000-00000083
T 7 00000000-00000003
S 2 00000000-00000007
T 80 00000000-00000007
R 1 00000000-00000005
S 63 80000000-00000005
S 32 80000001-00000005
R 63 00000001-00000005
T 62 40000001-00000005
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint32_t err1 = 0;
static uint32_t err2 = 0;
#define SET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 |= (1U<<(x))):
(err2 |= (1U<<((x)-32)))
)
#define RESET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 &= ~(1U<<(x))):
(err2 &= ~(1U<<((x)-32)))
)
#define TOGGLE_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 ^= (1U<<(x))):
(err2 ^= (1U<<((x)-32)))
)
int main(int argc, char *argv)
{
int i;
unsigned int x;
for(i=1;i<argc;i+=2) {
x=strtoul(argv[i+1],NULL,0);
switch (argv[i][0]) {
case 'S':
SET_ERROR_BIT(x);
break;
case 'T':
TOGGLE_ERROR_BIT(x);
break;
case 'R':
RESET_ERROR_BIT(x);
break;
default:
break;
}
printf("%c %2d %08X-%08Xn",argv[i][0], x, err2, err1);
}
return 0;
}
The macros are splitted in more then one line, but they are each a one-line code.
The code main has no error control then if the parameters are not correctly specified the program might be undefined behaviour.
OP's code handledx < 0. This answer, like first one, has vulnerability whenx < 0.
– chux
Nov 26 '18 at 13:32
It's not a vulnerability to avoid the x<0 control, because the input variable should be considered an unsigned at compilation time. If you use an int the code will be compiled with error. If you force the variable at a negative value the code will consider the value as a number greater or equal to 0, so it is sufficient to consider the control on greater than 63.
– Sir Jo Black
Nov 26 '18 at 13:37
1
Disagree with "because the input variable should be considered an unsigned at compilation time". Enumerated values are not certainly unsigned ref and OP wisely wants to prevent possibility withif(x < 0
– chux
Nov 26 '18 at 13:42
In the code I've implemented the variable x is an unsigned. May be I'm OT.
– Sir Jo Black
Nov 26 '18 at 13:46
@Chux, I understood your point of view :)
– Sir Jo Black
Nov 26 '18 at 13:50
add a comment |
Seeing the thread I wanted to indicate a nice (and perhaps cleaner) way to set, reset and toggle the status of a bit in the case of the two unsigned integers as in thread. This code should be OT because uses x that shall be an unsigned int (or an int) and not a enum value.
I've written the line of code at the end of this answer.
The code receives as input a number of parameter couples. Each couple of parameter is a letter and a number. The letter may be:
- S to set a bit
- R to reset a bit
- T to toggle a bit
The number has to be a bit value from 0 to 63. The macros in the code discard each number greater than 63 and nothing is modified into the variables. The negative values haven't been evalued because we suppose a bit value is an unsigned value.
For Example (if we name the program bitman):
Executing: bitman S 0 S 1 T 7 S 64 T 7 S 2 T 80 R 1 S 63 S 32 R 63 T 62
The output will be:
S 0 00000000-00000001
S 1 00000000-00000003
T 7 00000000-00000083
S 64 00000000-00000083
T 7 00000000-00000003
S 2 00000000-00000007
T 80 00000000-00000007
R 1 00000000-00000005
S 63 80000000-00000005
S 32 80000001-00000005
R 63 00000001-00000005
T 62 40000001-00000005
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint32_t err1 = 0;
static uint32_t err2 = 0;
#define SET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 |= (1U<<(x))):
(err2 |= (1U<<((x)-32)))
)
#define RESET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 &= ~(1U<<(x))):
(err2 &= ~(1U<<((x)-32)))
)
#define TOGGLE_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 ^= (1U<<(x))):
(err2 ^= (1U<<((x)-32)))
)
int main(int argc, char *argv)
{
int i;
unsigned int x;
for(i=1;i<argc;i+=2) {
x=strtoul(argv[i+1],NULL,0);
switch (argv[i][0]) {
case 'S':
SET_ERROR_BIT(x);
break;
case 'T':
TOGGLE_ERROR_BIT(x);
break;
case 'R':
RESET_ERROR_BIT(x);
break;
default:
break;
}
printf("%c %2d %08X-%08Xn",argv[i][0], x, err2, err1);
}
return 0;
}
The macros are splitted in more then one line, but they are each a one-line code.
The code main has no error control then if the parameters are not correctly specified the program might be undefined behaviour.
OP's code handledx < 0. This answer, like first one, has vulnerability whenx < 0.
– chux
Nov 26 '18 at 13:32
It's not a vulnerability to avoid the x<0 control, because the input variable should be considered an unsigned at compilation time. If you use an int the code will be compiled with error. If you force the variable at a negative value the code will consider the value as a number greater or equal to 0, so it is sufficient to consider the control on greater than 63.
– Sir Jo Black
Nov 26 '18 at 13:37
1
Disagree with "because the input variable should be considered an unsigned at compilation time". Enumerated values are not certainly unsigned ref and OP wisely wants to prevent possibility withif(x < 0
– chux
Nov 26 '18 at 13:42
In the code I've implemented the variable x is an unsigned. May be I'm OT.
– Sir Jo Black
Nov 26 '18 at 13:46
@Chux, I understood your point of view :)
– Sir Jo Black
Nov 26 '18 at 13:50
add a comment |
Seeing the thread I wanted to indicate a nice (and perhaps cleaner) way to set, reset and toggle the status of a bit in the case of the two unsigned integers as in thread. This code should be OT because uses x that shall be an unsigned int (or an int) and not a enum value.
I've written the line of code at the end of this answer.
The code receives as input a number of parameter couples. Each couple of parameter is a letter and a number. The letter may be:
- S to set a bit
- R to reset a bit
- T to toggle a bit
The number has to be a bit value from 0 to 63. The macros in the code discard each number greater than 63 and nothing is modified into the variables. The negative values haven't been evalued because we suppose a bit value is an unsigned value.
For Example (if we name the program bitman):
Executing: bitman S 0 S 1 T 7 S 64 T 7 S 2 T 80 R 1 S 63 S 32 R 63 T 62
The output will be:
S 0 00000000-00000001
S 1 00000000-00000003
T 7 00000000-00000083
S 64 00000000-00000083
T 7 00000000-00000003
S 2 00000000-00000007
T 80 00000000-00000007
R 1 00000000-00000005
S 63 80000000-00000005
S 32 80000001-00000005
R 63 00000001-00000005
T 62 40000001-00000005
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint32_t err1 = 0;
static uint32_t err2 = 0;
#define SET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 |= (1U<<(x))):
(err2 |= (1U<<((x)-32)))
)
#define RESET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 &= ~(1U<<(x))):
(err2 &= ~(1U<<((x)-32)))
)
#define TOGGLE_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 ^= (1U<<(x))):
(err2 ^= (1U<<((x)-32)))
)
int main(int argc, char *argv)
{
int i;
unsigned int x;
for(i=1;i<argc;i+=2) {
x=strtoul(argv[i+1],NULL,0);
switch (argv[i][0]) {
case 'S':
SET_ERROR_BIT(x);
break;
case 'T':
TOGGLE_ERROR_BIT(x);
break;
case 'R':
RESET_ERROR_BIT(x);
break;
default:
break;
}
printf("%c %2d %08X-%08Xn",argv[i][0], x, err2, err1);
}
return 0;
}
The macros are splitted in more then one line, but they are each a one-line code.
The code main has no error control then if the parameters are not correctly specified the program might be undefined behaviour.
Seeing the thread I wanted to indicate a nice (and perhaps cleaner) way to set, reset and toggle the status of a bit in the case of the two unsigned integers as in thread. This code should be OT because uses x that shall be an unsigned int (or an int) and not a enum value.
I've written the line of code at the end of this answer.
The code receives as input a number of parameter couples. Each couple of parameter is a letter and a number. The letter may be:
- S to set a bit
- R to reset a bit
- T to toggle a bit
The number has to be a bit value from 0 to 63. The macros in the code discard each number greater than 63 and nothing is modified into the variables. The negative values haven't been evalued because we suppose a bit value is an unsigned value.
For Example (if we name the program bitman):
Executing: bitman S 0 S 1 T 7 S 64 T 7 S 2 T 80 R 1 S 63 S 32 R 63 T 62
The output will be:
S 0 00000000-00000001
S 1 00000000-00000003
T 7 00000000-00000083
S 64 00000000-00000083
T 7 00000000-00000003
S 2 00000000-00000007
T 80 00000000-00000007
R 1 00000000-00000005
S 63 80000000-00000005
S 32 80000001-00000005
R 63 00000001-00000005
T 62 40000001-00000005
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint32_t err1 = 0;
static uint32_t err2 = 0;
#define SET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 |= (1U<<(x))):
(err2 |= (1U<<((x)-32)))
)
#define RESET_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 &= ~(1U<<(x))):
(err2 &= ~(1U<<((x)-32)))
)
#define TOGGLE_ERROR_BIT(x) (
((unsigned)(x)>63)?err1=err1:((x)<32)?
(err1 ^= (1U<<(x))):
(err2 ^= (1U<<((x)-32)))
)
int main(int argc, char *argv)
{
int i;
unsigned int x;
for(i=1;i<argc;i+=2) {
x=strtoul(argv[i+1],NULL,0);
switch (argv[i][0]) {
case 'S':
SET_ERROR_BIT(x);
break;
case 'T':
TOGGLE_ERROR_BIT(x);
break;
case 'R':
RESET_ERROR_BIT(x);
break;
default:
break;
}
printf("%c %2d %08X-%08Xn",argv[i][0], x, err2, err1);
}
return 0;
}
The macros are splitted in more then one line, but they are each a one-line code.
The code main has no error control then if the parameters are not correctly specified the program might be undefined behaviour.
edited Nov 26 '18 at 14:59
answered Nov 26 '18 at 13:28
Sir Jo BlackSir Jo Black
1,291918
1,291918
OP's code handledx < 0. This answer, like first one, has vulnerability whenx < 0.
– chux
Nov 26 '18 at 13:32
It's not a vulnerability to avoid the x<0 control, because the input variable should be considered an unsigned at compilation time. If you use an int the code will be compiled with error. If you force the variable at a negative value the code will consider the value as a number greater or equal to 0, so it is sufficient to consider the control on greater than 63.
– Sir Jo Black
Nov 26 '18 at 13:37
1
Disagree with "because the input variable should be considered an unsigned at compilation time". Enumerated values are not certainly unsigned ref and OP wisely wants to prevent possibility withif(x < 0
– chux
Nov 26 '18 at 13:42
In the code I've implemented the variable x is an unsigned. May be I'm OT.
– Sir Jo Black
Nov 26 '18 at 13:46
@Chux, I understood your point of view :)
– Sir Jo Black
Nov 26 '18 at 13:50
add a comment |
OP's code handledx < 0. This answer, like first one, has vulnerability whenx < 0.
– chux
Nov 26 '18 at 13:32
It's not a vulnerability to avoid the x<0 control, because the input variable should be considered an unsigned at compilation time. If you use an int the code will be compiled with error. If you force the variable at a negative value the code will consider the value as a number greater or equal to 0, so it is sufficient to consider the control on greater than 63.
– Sir Jo Black
Nov 26 '18 at 13:37
1
Disagree with "because the input variable should be considered an unsigned at compilation time". Enumerated values are not certainly unsigned ref and OP wisely wants to prevent possibility withif(x < 0
– chux
Nov 26 '18 at 13:42
In the code I've implemented the variable x is an unsigned. May be I'm OT.
– Sir Jo Black
Nov 26 '18 at 13:46
@Chux, I understood your point of view :)
– Sir Jo Black
Nov 26 '18 at 13:50
OP's code handled
x < 0. This answer, like first one, has vulnerability when x < 0.– chux
Nov 26 '18 at 13:32
OP's code handled
x < 0. This answer, like first one, has vulnerability when x < 0.– chux
Nov 26 '18 at 13:32
It's not a vulnerability to avoid the x<0 control, because the input variable should be considered an unsigned at compilation time. If you use an int the code will be compiled with error. If you force the variable at a negative value the code will consider the value as a number greater or equal to 0, so it is sufficient to consider the control on greater than 63.
– Sir Jo Black
Nov 26 '18 at 13:37
It's not a vulnerability to avoid the x<0 control, because the input variable should be considered an unsigned at compilation time. If you use an int the code will be compiled with error. If you force the variable at a negative value the code will consider the value as a number greater or equal to 0, so it is sufficient to consider the control on greater than 63.
– Sir Jo Black
Nov 26 '18 at 13:37
1
1
Disagree with "because the input variable should be considered an unsigned at compilation time". Enumerated values are not certainly unsigned ref and OP wisely wants to prevent possibility with
if(x < 0– chux
Nov 26 '18 at 13:42
Disagree with "because the input variable should be considered an unsigned at compilation time". Enumerated values are not certainly unsigned ref and OP wisely wants to prevent possibility with
if(x < 0– chux
Nov 26 '18 at 13:42
In the code I've implemented the variable x is an unsigned. May be I'm OT.
– Sir Jo Black
Nov 26 '18 at 13:46
In the code I've implemented the variable x is an unsigned. May be I'm OT.
– Sir Jo Black
Nov 26 '18 at 13:46
@Chux, I understood your point of view :)
– Sir Jo Black
Nov 26 '18 at 13:50
@Chux, I understood your point of view :)
– Sir Jo Black
Nov 26 '18 at 13:50
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%2f53479744%2fleft-shift-count-width-of-type-in-c-macro%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

1
show where the macro is called also
– LoPiTaL
Nov 26 '18 at 11:06
I have edited the post.
– Vincent Fartmann
Nov 26 '18 at 11:09
1
This (and I really don't mean to cause offence here) truly hideous beast is a classic example of why macros are a bad idea for anything other than simple true/false things in modern C compilers. You could write something far more readable with a function that generally has little performance impact, if any. I always try to optimise for readabilty first :-)
– paxdiablo
Nov 26 '18 at 11:09
I already thought of writing a function for this, but i want to figure out why the warning is produced
– Vincent Fartmann
Nov 26 '18 at 11:12
4
In the macros, you distinguish two cases, which, on their own, are okay. The warning comes from the branch that isn't executed, where the shift is out of range. (Apparently these disgnostics are issued before the dead branch is eliminated.)
– M Oehm
Nov 26 '18 at 11:16