1

given this operation:

int64_t a_int64, b_int64 = WHATEVER1;
int32_t c_int32 = WHATEVER2;

a_int64 = b_int64 - (c_int32 * 1000000);

Is c_int32 promoted to int64_t before the multiply? I know all integers are promoted to at least 'int' size before any arithmetic operations, and to the size of the larger operand for binary operators if this is of greater rank than an int. But are operations inside parentheses' are handled separately from the (second) operation, the substraction?

ElkeAusBerlin
  • 565
  • 1
  • 4
  • 18
  • 2
    to be sure - just use `1000000ULL` to indicate that both arguments of the multiplication should be promoted to at least 64 bits – Iłya Bursov Feb 26 '16 at 16:35
  • 3
    Note: `()` are parentheses. Brackets are `[]`. – too honest for this site Feb 26 '16 at 16:38
  • 1
    @Lashane: Correct would be using the `INT64_C` macro. And OP uses signed integers, suffix `U` is wrong. – too honest for this site Feb 26 '16 at 16:41
  • 2
    @Ian: If it overflows, it's undefined behavior. You *can't* test for undefined behavior. – EOF Feb 26 '16 at 16:42
  • @EOF if we get it overflow, then we already get our answer actually - it is not promoted. No? – Ian Feb 26 '16 at 16:43
  • @Olaf yeah, `U` should not be used here. But `LL` should be - as OP wants 64 bit multiplication – Iłya Bursov Feb 26 '16 at 16:44
  • @Ian: If it overflows, the compiler is free to do whatever it wants, including doing the multiplication at 64-bit width *in your tests only*, while failing when you try to use this outside of testing. – EOF Feb 26 '16 at 16:45
  • @Lashane: No, as I wrote, he should use the macro, not `LL` suffix. – too honest for this site Feb 26 '16 at 16:45
  • @EOF ah, I see. I get it now. – Ian Feb 26 '16 at 16:45
  • @Ian, per definition the compiler is allowed to throw a dice how to handle undefined behavior. (Overflows for signed numbers are not specified, only the wrap around for unsigned numbers.) – Kijewski Feb 26 '16 at 16:46
  • @Kay I see. Thanks for clarifying further... – Ian Feb 26 '16 at 16:47
  • @Olaf, why do you insist of the macro? – SergeyA Feb 26 '16 at 16:54
  • @Olaf if this macro is defined - great, lets use it, if not - lets use traditional postfixes – Iłya Bursov Feb 26 '16 at 16:57
  • The `(c_int32 * 1000000)` subexpression is evaluated as a 32-bit int, so it will probably overflow. – David R Tribble Feb 26 '16 at 17:00
  • @ryyker: No, the macro is standard C, see 7.20.4.1 – too honest for this site Feb 26 '16 at 17:07
  • @Lashane: It is part of `stdint.h`, thus standard and required. Don't believe every comment. – too honest for this site Feb 26 '16 at 17:09
  • @DavidRTribble: "is evaluated as a 32-bit int" only if `int` has exactly 32 used bits. Otherwise it is promoted to whatever type `int32_t` is, or the actual size of `int`, whichever is larger. – too honest for this site Feb 26 '16 at 17:10
  • @Olaf I don't believe comments, this macro is defined only if `__STDC_CONSTANT_MACROS` is defined – Iłya Bursov Feb 26 '16 at 17:17
  • @Lashane: Please point me at where the standard mentions that macro. I'm afraid, I cannot find it in the standard. And 7.20.4 does not mention the macro is optional either. – too honest for this site Feb 26 '16 at 17:31
  • @Lashane: You are aware C and C++ are different languages, are you? – too honest for this site Feb 26 '16 at 17:39
  • 1
    @Lashane Where is `__STDC_CONSTANT_MACROS` defined? I am not familiar with this macro. – chux - Reinstate Monica Feb 26 '16 at 18:05
  • @chux check out http://stackoverflow.com/questions/986426/what-do-stdc-limit-macros-and-stdc-constant-macros-mean – Iłya Bursov Feb 26 '16 at 18:05
  • @Lashane So it appears `__STDC_CONSTANT_MACROS` is defined neither in C, like this post's tag, nor specified to be in C++, yet it is common in many C++. It that it? – chux - Reinstate Monica Feb 26 '16 at 18:09
  • @chux afair its non standard extension to use some C macros/definitions in C++, as soon as people quite often use c++ compiler to compile c code (and mostly it works) - you need to define it by yourself – Iłya Bursov Feb 26 '16 at 18:11
  • @Olaf what is your point? I've already told you "if this macro is defined - great, lets use it, if not - lets use traditional postfixes". There are at least 2 situations when this macro is not defined (one is standard, one is non standard). – Iłya Bursov Feb 26 '16 at 18:13
  • @Lashane: Using a C++ compiler to compile C code is a very bad idea. Identical syntax does not imply identical semantics. And the question is tagged C, so we very well can assume a C compiler is used. I would also not compile C code with a Java compiler or try make it compatible with Pytrhon. For C, the `INTn_C` macros are **always** present if `stdint.h` is present. As OP uses `int64_t` which is also defined in `stdint.h`, this is obviously true. – too honest for this site Feb 26 '16 at 18:16
  • 1
    @chux: Yes, thanks; remove the last sentence. I think you undersand why I added it (I was not the first to become personal, but should know better) ... – too honest for this site Feb 26 '16 at 18:20
  • @Olaf the more I work with different c/c++ compilers and libraries, the less I can assume anything, `int64_t` can be defined anywhere (in real world). So my point is still the same: sure that you can use macro, go ahead and use it, trying to be as portable as possible - use sub-set which is common for all standards. So, phrase `For C, the INTn_C macros are always present` - is *always* false :) – Iłya Bursov Feb 26 '16 at 18:32

2 Answers2

2

From another good SO post on the topic:

C99, §6.4.4.1

The type of an integer constant is the first of the corresponding list in which its value can be represented.

Table 6

int
long int
long long int

So, the automatic promotion of c_int32 will depend on the size of the integer literal. In this case, on a 32-bit system, your integer literal will easily fit within an in32_t variable.

This is not a good way to do integer arithmetic. Make your code as explicit as possible, and leave nothing to chance.

a_int64 = b_int64 - ((int64_t)c_int32 * 1000000LL);
Cloud
  • 18,753
  • 15
  • 79
  • 153
  • This answer is not wrong, but instead of answering the OP's question, it presupposes the correct answer, in the middle of talking about other stuff. The OP asked a specific, reasonable question; any answer should, if nothing else, answer it. – ruakh Feb 26 '16 at 17:35
  • @ruakh I maintain that the above answers OP's question. It "depends" on the value of the literal itself. I note that on a 32-bit system, it will fit into a 32-bit `int`. To be more explicit, the literal will evaluate to an `int`, and for most possible values of `c_int32`, overflow will occur. The question is addressed, but perhaps not as explicitly as the audience requires. – Cloud Feb 26 '16 at 17:49
  • C standard is C11, not C99. An answer should cite from the standard. The final draft n1570 is available for free. And to provide a 64 bit `int` (or the smallest possible type), the `INT64_C` macro is a better choice. – too honest for this site Feb 26 '16 at 18:13
  • @Olaf, Agree widening the multiplication to `int64_t` with `INT64_C` or with `(int64_t)` is sufficient. Using `LL` works but may push the width unnecessarily, which I think is your point, say on a future system where `long long` is 128 bit. (I went through a similar issue [here](http://stackoverflow.com/q/19451101/2410359)) – chux - Reinstate Monica Feb 26 '16 at 18:24
  • @chux: Yes, that is the idea. On a defined target and with no portability in mind (e.g. an emedded system), I'm actually fine with the suffixes - mostly because I'm a lazy coder, too:-), but SO answers should look further and use the most correct code. – too honest for this site Feb 26 '16 at 18:31
  • @Dogbert: But the OP clearly already understood all of those things. His/her question was specifically about when the promotion to `int64_t` takes place. Your answer is basically nitpicking about the parts that the OP expressed less-precisely than you might have wanted, while taking for granted the parts that the OP actually sought an explanation for. – ruakh Feb 26 '16 at 23:12
2

But are operations inside parentheses' are handled separately from the (second) operation, the substraction?

Yes; the promotions involved in evaluating c_int32 * 1000000 do not depend in any way on the context. Any necessary conversions due to that context happen on the result, afterward.

That said, c_int32 * 1000000 is only well-defined in cases where it doesn't overflow; and in such cases, it doesn't matter whether the 64-bit promotion happens before or after the multiplication. So a compiler could legitimately do it either way (e.g., if it sees some optimization opportunity).

ruakh
  • 175,680
  • 26
  • 273
  • 307