Arduino: incorrect calculation of long integer
I'm doing a simple calculation with integers (on Arduino with ESP8266 12E), but I can't get the expected result and can't find the error. Can someone guide me?
#define A 200
#define B A * 62
#define C 500
void setup() {
Serial.begin(9600);
Serial.println("");
unsigned long aux = 0;
aux = (B * 500) / C; // (12400 * 500) / 500 = 12400
Serial.printf("aux = %dn", aux);
aux = aux * C; // 12400 * 500 = 6200000
Serial.printf("aux = %dn", aux);
// ERROR: Should result in "500", but is resulting in "1922000"
aux = aux / B; // 6200000 / 12400 = 500
Serial.printf("aux = %dn", aux); // It's printing "1922000"
}
esp8266
migrated from electronics.stackexchange.com Dec 28 '18 at 16:41
This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.
add a comment |
I'm doing a simple calculation with integers (on Arduino with ESP8266 12E), but I can't get the expected result and can't find the error. Can someone guide me?
#define A 200
#define B A * 62
#define C 500
void setup() {
Serial.begin(9600);
Serial.println("");
unsigned long aux = 0;
aux = (B * 500) / C; // (12400 * 500) / 500 = 12400
Serial.printf("aux = %dn", aux);
aux = aux * C; // 12400 * 500 = 6200000
Serial.printf("aux = %dn", aux);
// ERROR: Should result in "500", but is resulting in "1922000"
aux = aux / B; // 6200000 / 12400 = 500
Serial.printf("aux = %dn", aux); // It's printing "1922000"
}
esp8266
migrated from electronics.stackexchange.com Dec 28 '18 at 16:41
This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.
add a comment |
I'm doing a simple calculation with integers (on Arduino with ESP8266 12E), but I can't get the expected result and can't find the error. Can someone guide me?
#define A 200
#define B A * 62
#define C 500
void setup() {
Serial.begin(9600);
Serial.println("");
unsigned long aux = 0;
aux = (B * 500) / C; // (12400 * 500) / 500 = 12400
Serial.printf("aux = %dn", aux);
aux = aux * C; // 12400 * 500 = 6200000
Serial.printf("aux = %dn", aux);
// ERROR: Should result in "500", but is resulting in "1922000"
aux = aux / B; // 6200000 / 12400 = 500
Serial.printf("aux = %dn", aux); // It's printing "1922000"
}
esp8266
I'm doing a simple calculation with integers (on Arduino with ESP8266 12E), but I can't get the expected result and can't find the error. Can someone guide me?
#define A 200
#define B A * 62
#define C 500
void setup() {
Serial.begin(9600);
Serial.println("");
unsigned long aux = 0;
aux = (B * 500) / C; // (12400 * 500) / 500 = 12400
Serial.printf("aux = %dn", aux);
aux = aux * C; // 12400 * 500 = 6200000
Serial.printf("aux = %dn", aux);
// ERROR: Should result in "500", but is resulting in "1922000"
aux = aux / B; // 6200000 / 12400 = 500
Serial.printf("aux = %dn", aux); // It's printing "1922000"
}
esp8266
esp8266
asked Dec 28 '18 at 14:20
wBBwBB
1135
1135
migrated from electronics.stackexchange.com Dec 28 '18 at 16:41
This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.
migrated from electronics.stackexchange.com Dec 28 '18 at 16:41
This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
In your #define of B you missed parenthesis (). Change your definition to:
#define B (A * 62)
Without parenthesis you first divide 6200000 by 200 and then multiply result by 62, which is not what you intend.
Dude, you're 100% right. I've spent several hours trying to figure out what was wrong ... Thank you so much!
– wBB
Dec 28 '18 at 14:44
2
@wBB remember that in C, macros are replaced in the code, exactly as you wrote them, in the preprocessor step before the code gets compiled. So it helps as a sanity-check in these cases to expand the macros yourself in your code to see if you're getting what you intended.
– brhans
Dec 28 '18 at 15:19
It really is was my lack of exeperience in C that led me to the problem. Thanks!
– wBB
Dec 28 '18 at 18:18
add a comment |
Fully-parenthesizing macros (as noted in answer by dmz) solves one class of problem.
Another thing you should do is, in any arithmetic expression which involves literal constants, use the L
suffix on at least one of the constants involved if there's any chance the result will exceed 32767 (the maximum guaranteed-representable value for int
). The type of an arithmetic operation in C is based on the types of the operands of that operation only; the type of the variable to which the result is assigned is irrelevant.
(edit)
For example:
long q, r;
unsigned char v = 231;
unsigned char w = 197;
q = v * w * 5;
r = v * w * 5L;
q
might contain 30927, since after the Usual Arithmetic Conversions (6.3.1.8) [in this case, the Integer Promotions (6.3.1.1-2)] all operands are of type int
and it's possible for INT_MAX
to be 32767 in which case each operation would be performed modulo 32768.
r
will contain 227535, since the constant 5L
is of type long
and thus all operations in this expression will be performed on values of type long
.
2
...and the format specifier for anunsigned long
is%lu
not%d
- the compiler for the asker's esp8266 uses a 32-bitint
so they get away with some things they would not on an ATmega-based Arduino where anint
is the minimum 16 bit size allowed by the specification.
– Chris Stratton
Dec 28 '18 at 16:27
@mlp usually I use a typecast on almost everything. Example:int J = -1
, typecast(unsigned char) J //prints 255
. When you talk about the suffixL
, what do you mean? Can you give an example?
– wBB
Dec 28 '18 at 18:33
@ChrisStratton, thanks for explanation.
– wBB
Dec 28 '18 at 18:35
add a comment |
As explained in previous answers, fully parenthesizing the macros is the
standard solution to this problem in C. However, on Arduino you are
programming in C++, and in C++ it is considered good practice to replace
this usage of #define
by explicit constants:
const int A = 200;
const int B = A * 62;
const int C = 500;
Not only this makes the initial problem go away, it also provides some
type safety: you can choose to give these constants other types (e.g.
long
) if appropriate.
Some compilers will interpret "const" as a variable going into program memory which then in turn results in issues with memory spaces. Consts offer type protection, which can also be (partially) achieved by casting inside the define "#define A ((int)200)" for instance.
– le_top
Dec 30 '18 at 0:08
@le_top: Do you have a specific example of the kind of “issues with memory spaces” you can get? I doubt you could find an example that does not invoke undefined behavior.
– Edgar Bonet
Dec 30 '18 at 10:08
Something along these lines for example: "const int a=100; int b=200; void setB(const int *c) {b=c;} void ex1() {setB(&a);}" . But there are other cases. When "const" puts "a" in ROM, some embedded compilers can not cope with this kind of assignment and do not report all violating cases. So I tend to put "CONST" if there is a future risk for this. (with a "#define CONST const" if possible).
– le_top
Dec 30 '18 at 18:23
@le_top: I guess you meanb=*c
. This sounds like a compiler bug to me. What compiler had issues with this? I tried your code on avr-gcc, and it had no issues, even when I replacedconst
by__flash const
, which has the effect of puttinga
in flash.
– Edgar Bonet
Dec 30 '18 at 20:35
Yes, b=*c. It will depend on the compiler and the uC. I file reports when I find bugs - when the compiler does not warn about it it is a bug, but otherwise it is a documented limitation.On Arduino you should use PROGMEM rather than __flash. I do not want to put a specific compilrer forward, my comment was mainly about warning that there are compilers for embedded systems that interpret const in a way that breaks code compatibility. That's also why you're required to add "__flash" to get the variable in FLASH - keeping it in RAM eases code generation (and speed) for those processors.
– le_top
Dec 31 '18 at 11:19
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("schematics", function () {
StackExchange.schematics.init();
});
}, "cicuitlab");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "540"
};
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: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
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%2farduino.stackexchange.com%2fquestions%2f60097%2farduino-incorrect-calculation-of-long-integer%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
In your #define of B you missed parenthesis (). Change your definition to:
#define B (A * 62)
Without parenthesis you first divide 6200000 by 200 and then multiply result by 62, which is not what you intend.
Dude, you're 100% right. I've spent several hours trying to figure out what was wrong ... Thank you so much!
– wBB
Dec 28 '18 at 14:44
2
@wBB remember that in C, macros are replaced in the code, exactly as you wrote them, in the preprocessor step before the code gets compiled. So it helps as a sanity-check in these cases to expand the macros yourself in your code to see if you're getting what you intended.
– brhans
Dec 28 '18 at 15:19
It really is was my lack of exeperience in C that led me to the problem. Thanks!
– wBB
Dec 28 '18 at 18:18
add a comment |
In your #define of B you missed parenthesis (). Change your definition to:
#define B (A * 62)
Without parenthesis you first divide 6200000 by 200 and then multiply result by 62, which is not what you intend.
Dude, you're 100% right. I've spent several hours trying to figure out what was wrong ... Thank you so much!
– wBB
Dec 28 '18 at 14:44
2
@wBB remember that in C, macros are replaced in the code, exactly as you wrote them, in the preprocessor step before the code gets compiled. So it helps as a sanity-check in these cases to expand the macros yourself in your code to see if you're getting what you intended.
– brhans
Dec 28 '18 at 15:19
It really is was my lack of exeperience in C that led me to the problem. Thanks!
– wBB
Dec 28 '18 at 18:18
add a comment |
In your #define of B you missed parenthesis (). Change your definition to:
#define B (A * 62)
Without parenthesis you first divide 6200000 by 200 and then multiply result by 62, which is not what you intend.
In your #define of B you missed parenthesis (). Change your definition to:
#define B (A * 62)
Without parenthesis you first divide 6200000 by 200 and then multiply result by 62, which is not what you intend.
answered Dec 28 '18 at 14:41
dmz
Dude, you're 100% right. I've spent several hours trying to figure out what was wrong ... Thank you so much!
– wBB
Dec 28 '18 at 14:44
2
@wBB remember that in C, macros are replaced in the code, exactly as you wrote them, in the preprocessor step before the code gets compiled. So it helps as a sanity-check in these cases to expand the macros yourself in your code to see if you're getting what you intended.
– brhans
Dec 28 '18 at 15:19
It really is was my lack of exeperience in C that led me to the problem. Thanks!
– wBB
Dec 28 '18 at 18:18
add a comment |
Dude, you're 100% right. I've spent several hours trying to figure out what was wrong ... Thank you so much!
– wBB
Dec 28 '18 at 14:44
2
@wBB remember that in C, macros are replaced in the code, exactly as you wrote them, in the preprocessor step before the code gets compiled. So it helps as a sanity-check in these cases to expand the macros yourself in your code to see if you're getting what you intended.
– brhans
Dec 28 '18 at 15:19
It really is was my lack of exeperience in C that led me to the problem. Thanks!
– wBB
Dec 28 '18 at 18:18
Dude, you're 100% right. I've spent several hours trying to figure out what was wrong ... Thank you so much!
– wBB
Dec 28 '18 at 14:44
Dude, you're 100% right. I've spent several hours trying to figure out what was wrong ... Thank you so much!
– wBB
Dec 28 '18 at 14:44
2
2
@wBB remember that in C, macros are replaced in the code, exactly as you wrote them, in the preprocessor step before the code gets compiled. So it helps as a sanity-check in these cases to expand the macros yourself in your code to see if you're getting what you intended.
– brhans
Dec 28 '18 at 15:19
@wBB remember that in C, macros are replaced in the code, exactly as you wrote them, in the preprocessor step before the code gets compiled. So it helps as a sanity-check in these cases to expand the macros yourself in your code to see if you're getting what you intended.
– brhans
Dec 28 '18 at 15:19
It really is was my lack of exeperience in C that led me to the problem. Thanks!
– wBB
Dec 28 '18 at 18:18
It really is was my lack of exeperience in C that led me to the problem. Thanks!
– wBB
Dec 28 '18 at 18:18
add a comment |
Fully-parenthesizing macros (as noted in answer by dmz) solves one class of problem.
Another thing you should do is, in any arithmetic expression which involves literal constants, use the L
suffix on at least one of the constants involved if there's any chance the result will exceed 32767 (the maximum guaranteed-representable value for int
). The type of an arithmetic operation in C is based on the types of the operands of that operation only; the type of the variable to which the result is assigned is irrelevant.
(edit)
For example:
long q, r;
unsigned char v = 231;
unsigned char w = 197;
q = v * w * 5;
r = v * w * 5L;
q
might contain 30927, since after the Usual Arithmetic Conversions (6.3.1.8) [in this case, the Integer Promotions (6.3.1.1-2)] all operands are of type int
and it's possible for INT_MAX
to be 32767 in which case each operation would be performed modulo 32768.
r
will contain 227535, since the constant 5L
is of type long
and thus all operations in this expression will be performed on values of type long
.
2
...and the format specifier for anunsigned long
is%lu
not%d
- the compiler for the asker's esp8266 uses a 32-bitint
so they get away with some things they would not on an ATmega-based Arduino where anint
is the minimum 16 bit size allowed by the specification.
– Chris Stratton
Dec 28 '18 at 16:27
@mlp usually I use a typecast on almost everything. Example:int J = -1
, typecast(unsigned char) J //prints 255
. When you talk about the suffixL
, what do you mean? Can you give an example?
– wBB
Dec 28 '18 at 18:33
@ChrisStratton, thanks for explanation.
– wBB
Dec 28 '18 at 18:35
add a comment |
Fully-parenthesizing macros (as noted in answer by dmz) solves one class of problem.
Another thing you should do is, in any arithmetic expression which involves literal constants, use the L
suffix on at least one of the constants involved if there's any chance the result will exceed 32767 (the maximum guaranteed-representable value for int
). The type of an arithmetic operation in C is based on the types of the operands of that operation only; the type of the variable to which the result is assigned is irrelevant.
(edit)
For example:
long q, r;
unsigned char v = 231;
unsigned char w = 197;
q = v * w * 5;
r = v * w * 5L;
q
might contain 30927, since after the Usual Arithmetic Conversions (6.3.1.8) [in this case, the Integer Promotions (6.3.1.1-2)] all operands are of type int
and it's possible for INT_MAX
to be 32767 in which case each operation would be performed modulo 32768.
r
will contain 227535, since the constant 5L
is of type long
and thus all operations in this expression will be performed on values of type long
.
2
...and the format specifier for anunsigned long
is%lu
not%d
- the compiler for the asker's esp8266 uses a 32-bitint
so they get away with some things they would not on an ATmega-based Arduino where anint
is the minimum 16 bit size allowed by the specification.
– Chris Stratton
Dec 28 '18 at 16:27
@mlp usually I use a typecast on almost everything. Example:int J = -1
, typecast(unsigned char) J //prints 255
. When you talk about the suffixL
, what do you mean? Can you give an example?
– wBB
Dec 28 '18 at 18:33
@ChrisStratton, thanks for explanation.
– wBB
Dec 28 '18 at 18:35
add a comment |
Fully-parenthesizing macros (as noted in answer by dmz) solves one class of problem.
Another thing you should do is, in any arithmetic expression which involves literal constants, use the L
suffix on at least one of the constants involved if there's any chance the result will exceed 32767 (the maximum guaranteed-representable value for int
). The type of an arithmetic operation in C is based on the types of the operands of that operation only; the type of the variable to which the result is assigned is irrelevant.
(edit)
For example:
long q, r;
unsigned char v = 231;
unsigned char w = 197;
q = v * w * 5;
r = v * w * 5L;
q
might contain 30927, since after the Usual Arithmetic Conversions (6.3.1.8) [in this case, the Integer Promotions (6.3.1.1-2)] all operands are of type int
and it's possible for INT_MAX
to be 32767 in which case each operation would be performed modulo 32768.
r
will contain 227535, since the constant 5L
is of type long
and thus all operations in this expression will be performed on values of type long
.
Fully-parenthesizing macros (as noted in answer by dmz) solves one class of problem.
Another thing you should do is, in any arithmetic expression which involves literal constants, use the L
suffix on at least one of the constants involved if there's any chance the result will exceed 32767 (the maximum guaranteed-representable value for int
). The type of an arithmetic operation in C is based on the types of the operands of that operation only; the type of the variable to which the result is assigned is irrelevant.
(edit)
For example:
long q, r;
unsigned char v = 231;
unsigned char w = 197;
q = v * w * 5;
r = v * w * 5L;
q
might contain 30927, since after the Usual Arithmetic Conversions (6.3.1.8) [in this case, the Integer Promotions (6.3.1.1-2)] all operands are of type int
and it's possible for INT_MAX
to be 32767 in which case each operation would be performed modulo 32768.
r
will contain 227535, since the constant 5L
is of type long
and thus all operations in this expression will be performed on values of type long
.
edited Dec 31 '18 at 20:51
answered Dec 28 '18 at 16:23
mlpmlp
1312
1312
2
...and the format specifier for anunsigned long
is%lu
not%d
- the compiler for the asker's esp8266 uses a 32-bitint
so they get away with some things they would not on an ATmega-based Arduino where anint
is the minimum 16 bit size allowed by the specification.
– Chris Stratton
Dec 28 '18 at 16:27
@mlp usually I use a typecast on almost everything. Example:int J = -1
, typecast(unsigned char) J //prints 255
. When you talk about the suffixL
, what do you mean? Can you give an example?
– wBB
Dec 28 '18 at 18:33
@ChrisStratton, thanks for explanation.
– wBB
Dec 28 '18 at 18:35
add a comment |
2
...and the format specifier for anunsigned long
is%lu
not%d
- the compiler for the asker's esp8266 uses a 32-bitint
so they get away with some things they would not on an ATmega-based Arduino where anint
is the minimum 16 bit size allowed by the specification.
– Chris Stratton
Dec 28 '18 at 16:27
@mlp usually I use a typecast on almost everything. Example:int J = -1
, typecast(unsigned char) J //prints 255
. When you talk about the suffixL
, what do you mean? Can you give an example?
– wBB
Dec 28 '18 at 18:33
@ChrisStratton, thanks for explanation.
– wBB
Dec 28 '18 at 18:35
2
2
...and the format specifier for an
unsigned long
is %lu
not %d
- the compiler for the asker's esp8266 uses a 32-bit int
so they get away with some things they would not on an ATmega-based Arduino where an int
is the minimum 16 bit size allowed by the specification.– Chris Stratton
Dec 28 '18 at 16:27
...and the format specifier for an
unsigned long
is %lu
not %d
- the compiler for the asker's esp8266 uses a 32-bit int
so they get away with some things they would not on an ATmega-based Arduino where an int
is the minimum 16 bit size allowed by the specification.– Chris Stratton
Dec 28 '18 at 16:27
@mlp usually I use a typecast on almost everything. Example:
int J = -1
, typecast (unsigned char) J //prints 255
. When you talk about the suffix L
, what do you mean? Can you give an example?– wBB
Dec 28 '18 at 18:33
@mlp usually I use a typecast on almost everything. Example:
int J = -1
, typecast (unsigned char) J //prints 255
. When you talk about the suffix L
, what do you mean? Can you give an example?– wBB
Dec 28 '18 at 18:33
@ChrisStratton, thanks for explanation.
– wBB
Dec 28 '18 at 18:35
@ChrisStratton, thanks for explanation.
– wBB
Dec 28 '18 at 18:35
add a comment |
As explained in previous answers, fully parenthesizing the macros is the
standard solution to this problem in C. However, on Arduino you are
programming in C++, and in C++ it is considered good practice to replace
this usage of #define
by explicit constants:
const int A = 200;
const int B = A * 62;
const int C = 500;
Not only this makes the initial problem go away, it also provides some
type safety: you can choose to give these constants other types (e.g.
long
) if appropriate.
Some compilers will interpret "const" as a variable going into program memory which then in turn results in issues with memory spaces. Consts offer type protection, which can also be (partially) achieved by casting inside the define "#define A ((int)200)" for instance.
– le_top
Dec 30 '18 at 0:08
@le_top: Do you have a specific example of the kind of “issues with memory spaces” you can get? I doubt you could find an example that does not invoke undefined behavior.
– Edgar Bonet
Dec 30 '18 at 10:08
Something along these lines for example: "const int a=100; int b=200; void setB(const int *c) {b=c;} void ex1() {setB(&a);}" . But there are other cases. When "const" puts "a" in ROM, some embedded compilers can not cope with this kind of assignment and do not report all violating cases. So I tend to put "CONST" if there is a future risk for this. (with a "#define CONST const" if possible).
– le_top
Dec 30 '18 at 18:23
@le_top: I guess you meanb=*c
. This sounds like a compiler bug to me. What compiler had issues with this? I tried your code on avr-gcc, and it had no issues, even when I replacedconst
by__flash const
, which has the effect of puttinga
in flash.
– Edgar Bonet
Dec 30 '18 at 20:35
Yes, b=*c. It will depend on the compiler and the uC. I file reports when I find bugs - when the compiler does not warn about it it is a bug, but otherwise it is a documented limitation.On Arduino you should use PROGMEM rather than __flash. I do not want to put a specific compilrer forward, my comment was mainly about warning that there are compilers for embedded systems that interpret const in a way that breaks code compatibility. That's also why you're required to add "__flash" to get the variable in FLASH - keeping it in RAM eases code generation (and speed) for those processors.
– le_top
Dec 31 '18 at 11:19
add a comment |
As explained in previous answers, fully parenthesizing the macros is the
standard solution to this problem in C. However, on Arduino you are
programming in C++, and in C++ it is considered good practice to replace
this usage of #define
by explicit constants:
const int A = 200;
const int B = A * 62;
const int C = 500;
Not only this makes the initial problem go away, it also provides some
type safety: you can choose to give these constants other types (e.g.
long
) if appropriate.
Some compilers will interpret "const" as a variable going into program memory which then in turn results in issues with memory spaces. Consts offer type protection, which can also be (partially) achieved by casting inside the define "#define A ((int)200)" for instance.
– le_top
Dec 30 '18 at 0:08
@le_top: Do you have a specific example of the kind of “issues with memory spaces” you can get? I doubt you could find an example that does not invoke undefined behavior.
– Edgar Bonet
Dec 30 '18 at 10:08
Something along these lines for example: "const int a=100; int b=200; void setB(const int *c) {b=c;} void ex1() {setB(&a);}" . But there are other cases. When "const" puts "a" in ROM, some embedded compilers can not cope with this kind of assignment and do not report all violating cases. So I tend to put "CONST" if there is a future risk for this. (with a "#define CONST const" if possible).
– le_top
Dec 30 '18 at 18:23
@le_top: I guess you meanb=*c
. This sounds like a compiler bug to me. What compiler had issues with this? I tried your code on avr-gcc, and it had no issues, even when I replacedconst
by__flash const
, which has the effect of puttinga
in flash.
– Edgar Bonet
Dec 30 '18 at 20:35
Yes, b=*c. It will depend on the compiler and the uC. I file reports when I find bugs - when the compiler does not warn about it it is a bug, but otherwise it is a documented limitation.On Arduino you should use PROGMEM rather than __flash. I do not want to put a specific compilrer forward, my comment was mainly about warning that there are compilers for embedded systems that interpret const in a way that breaks code compatibility. That's also why you're required to add "__flash" to get the variable in FLASH - keeping it in RAM eases code generation (and speed) for those processors.
– le_top
Dec 31 '18 at 11:19
add a comment |
As explained in previous answers, fully parenthesizing the macros is the
standard solution to this problem in C. However, on Arduino you are
programming in C++, and in C++ it is considered good practice to replace
this usage of #define
by explicit constants:
const int A = 200;
const int B = A * 62;
const int C = 500;
Not only this makes the initial problem go away, it also provides some
type safety: you can choose to give these constants other types (e.g.
long
) if appropriate.
As explained in previous answers, fully parenthesizing the macros is the
standard solution to this problem in C. However, on Arduino you are
programming in C++, and in C++ it is considered good practice to replace
this usage of #define
by explicit constants:
const int A = 200;
const int B = A * 62;
const int C = 500;
Not only this makes the initial problem go away, it also provides some
type safety: you can choose to give these constants other types (e.g.
long
) if appropriate.
answered Dec 28 '18 at 18:53
Edgar BonetEdgar Bonet
24.1k22345
24.1k22345
Some compilers will interpret "const" as a variable going into program memory which then in turn results in issues with memory spaces. Consts offer type protection, which can also be (partially) achieved by casting inside the define "#define A ((int)200)" for instance.
– le_top
Dec 30 '18 at 0:08
@le_top: Do you have a specific example of the kind of “issues with memory spaces” you can get? I doubt you could find an example that does not invoke undefined behavior.
– Edgar Bonet
Dec 30 '18 at 10:08
Something along these lines for example: "const int a=100; int b=200; void setB(const int *c) {b=c;} void ex1() {setB(&a);}" . But there are other cases. When "const" puts "a" in ROM, some embedded compilers can not cope with this kind of assignment and do not report all violating cases. So I tend to put "CONST" if there is a future risk for this. (with a "#define CONST const" if possible).
– le_top
Dec 30 '18 at 18:23
@le_top: I guess you meanb=*c
. This sounds like a compiler bug to me. What compiler had issues with this? I tried your code on avr-gcc, and it had no issues, even when I replacedconst
by__flash const
, which has the effect of puttinga
in flash.
– Edgar Bonet
Dec 30 '18 at 20:35
Yes, b=*c. It will depend on the compiler and the uC. I file reports when I find bugs - when the compiler does not warn about it it is a bug, but otherwise it is a documented limitation.On Arduino you should use PROGMEM rather than __flash. I do not want to put a specific compilrer forward, my comment was mainly about warning that there are compilers for embedded systems that interpret const in a way that breaks code compatibility. That's also why you're required to add "__flash" to get the variable in FLASH - keeping it in RAM eases code generation (and speed) for those processors.
– le_top
Dec 31 '18 at 11:19
add a comment |
Some compilers will interpret "const" as a variable going into program memory which then in turn results in issues with memory spaces. Consts offer type protection, which can also be (partially) achieved by casting inside the define "#define A ((int)200)" for instance.
– le_top
Dec 30 '18 at 0:08
@le_top: Do you have a specific example of the kind of “issues with memory spaces” you can get? I doubt you could find an example that does not invoke undefined behavior.
– Edgar Bonet
Dec 30 '18 at 10:08
Something along these lines for example: "const int a=100; int b=200; void setB(const int *c) {b=c;} void ex1() {setB(&a);}" . But there are other cases. When "const" puts "a" in ROM, some embedded compilers can not cope with this kind of assignment and do not report all violating cases. So I tend to put "CONST" if there is a future risk for this. (with a "#define CONST const" if possible).
– le_top
Dec 30 '18 at 18:23
@le_top: I guess you meanb=*c
. This sounds like a compiler bug to me. What compiler had issues with this? I tried your code on avr-gcc, and it had no issues, even when I replacedconst
by__flash const
, which has the effect of puttinga
in flash.
– Edgar Bonet
Dec 30 '18 at 20:35
Yes, b=*c. It will depend on the compiler and the uC. I file reports when I find bugs - when the compiler does not warn about it it is a bug, but otherwise it is a documented limitation.On Arduino you should use PROGMEM rather than __flash. I do not want to put a specific compilrer forward, my comment was mainly about warning that there are compilers for embedded systems that interpret const in a way that breaks code compatibility. That's also why you're required to add "__flash" to get the variable in FLASH - keeping it in RAM eases code generation (and speed) for those processors.
– le_top
Dec 31 '18 at 11:19
Some compilers will interpret "const" as a variable going into program memory which then in turn results in issues with memory spaces. Consts offer type protection, which can also be (partially) achieved by casting inside the define "#define A ((int)200)" for instance.
– le_top
Dec 30 '18 at 0:08
Some compilers will interpret "const" as a variable going into program memory which then in turn results in issues with memory spaces. Consts offer type protection, which can also be (partially) achieved by casting inside the define "#define A ((int)200)" for instance.
– le_top
Dec 30 '18 at 0:08
@le_top: Do you have a specific example of the kind of “issues with memory spaces” you can get? I doubt you could find an example that does not invoke undefined behavior.
– Edgar Bonet
Dec 30 '18 at 10:08
@le_top: Do you have a specific example of the kind of “issues with memory spaces” you can get? I doubt you could find an example that does not invoke undefined behavior.
– Edgar Bonet
Dec 30 '18 at 10:08
Something along these lines for example: "const int a=100; int b=200; void setB(const int *c) {b=c;} void ex1() {setB(&a);}" . But there are other cases. When "const" puts "a" in ROM, some embedded compilers can not cope with this kind of assignment and do not report all violating cases. So I tend to put "CONST" if there is a future risk for this. (with a "#define CONST const" if possible).
– le_top
Dec 30 '18 at 18:23
Something along these lines for example: "const int a=100; int b=200; void setB(const int *c) {b=c;} void ex1() {setB(&a);}" . But there are other cases. When "const" puts "a" in ROM, some embedded compilers can not cope with this kind of assignment and do not report all violating cases. So I tend to put "CONST" if there is a future risk for this. (with a "#define CONST const" if possible).
– le_top
Dec 30 '18 at 18:23
@le_top: I guess you mean
b=*c
. This sounds like a compiler bug to me. What compiler had issues with this? I tried your code on avr-gcc, and it had no issues, even when I replaced const
by __flash const
, which has the effect of putting a
in flash.– Edgar Bonet
Dec 30 '18 at 20:35
@le_top: I guess you mean
b=*c
. This sounds like a compiler bug to me. What compiler had issues with this? I tried your code on avr-gcc, and it had no issues, even when I replaced const
by __flash const
, which has the effect of putting a
in flash.– Edgar Bonet
Dec 30 '18 at 20:35
Yes, b=*c. It will depend on the compiler and the uC. I file reports when I find bugs - when the compiler does not warn about it it is a bug, but otherwise it is a documented limitation.On Arduino you should use PROGMEM rather than __flash. I do not want to put a specific compilrer forward, my comment was mainly about warning that there are compilers for embedded systems that interpret const in a way that breaks code compatibility. That's also why you're required to add "__flash" to get the variable in FLASH - keeping it in RAM eases code generation (and speed) for those processors.
– le_top
Dec 31 '18 at 11:19
Yes, b=*c. It will depend on the compiler and the uC. I file reports when I find bugs - when the compiler does not warn about it it is a bug, but otherwise it is a documented limitation.On Arduino you should use PROGMEM rather than __flash. I do not want to put a specific compilrer forward, my comment was mainly about warning that there are compilers for embedded systems that interpret const in a way that breaks code compatibility. That's also why you're required to add "__flash" to get the variable in FLASH - keeping it in RAM eases code generation (and speed) for those processors.
– le_top
Dec 31 '18 at 11:19
add a comment |
Thanks for contributing an answer to Arduino Stack Exchange!
- 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%2farduino.stackexchange.com%2fquestions%2f60097%2farduino-incorrect-calculation-of-long-integer%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