1
int i;
long j;
unsigned int k;

I'm new to learning C, and can't figure this out. I've tried looking online many times for similar expressions. I honestly don't need the answer I really just want to understand how to figure it out. This has to do with mixing data types and I've only come across little information about what they are, but nothing clear to understand. Any help would be appreciated to understand how to figure out the data type for the following expression (long) i + (int) j * k

I appreciate any answers! Thank you!

cdaly_
  • 23
  • 6
  • 1
    What do *you* think? Why do you think that? Please [edit] your question to elaborate. – Some programmer dude Feb 10 '22 at 06:33
  • Also please read [How do I ask and answer homework questions?](https://meta.stackoverflow.com/questions/334822/how-do-i-ask-and-answer-homework-questions) as well as [Open letter to students with homework problems](https://softwareengineering.meta.stackexchange.com/questions/6166/open-letter-to-students-with-homework-problems) – Some programmer dude Feb 10 '22 at 06:33
  • C is regulated by ISO/IEC 9899 so you could try find out yourself and if you not sure what conclusion to make, provide what you had found. Note: In some cases answers to questions like that may depend on which version of that standard is used as a reference. In some cases you may find yourself dealing with a specialized, non-compliant compiler. – Swift - Friday Pie Feb 10 '22 at 06:39
  • Generally speaking, if multiple types are involved in an expressions, the compiler will implicitly convert values of smaller types with less precision into the larger types with more precision. The result is the largest type with the most precision. – Some programmer dude Feb 10 '22 at 06:52
  • @Someprogrammerdude I have tried many sources to get a little understanding of how and why data types conversion works. It's the one thing i'm struggling to understand. I'm not looking for just the answer, but to understand. – cdaly_ Feb 10 '22 at 06:57
  • Perhaps [this implicit conversion reference](https://en.cppreference.com/w/c/language/conversion) could be helpful. Also write down the actual types of each part of the expression on a piece of paper, to further help you. – Some programmer dude Feb 10 '22 at 07:02
  • @Someprogrammerdude I appreciate your help man. I'm new to all this, and I don't mean to come off as one of those guys that just wants to copy/paste code. I really want to learn. Thanks again. I'll take you up on your advice! – cdaly_ Feb 10 '22 at 07:22
  • 1
    @Swift-FridayPie: C is not regulated by ISO/IEC 9899. 9899 is a voluntary standard that ISO and IEC publish. It has no regulatory power. People may choose to conform or not. Many people do not. Some vendors cobble together compilers with their own C variants. GCC supports a GNU variant of C as an alternative to the ISO/IEC standard, and the GNU variant is the default. Even those who choose to use the standard often choose not to conform completely. – Eric Postpischil Feb 10 '22 at 10:33
  • @EricPostpischil I don't think that's entirely true. There's registered trademarks, false marketing and all manner of legal aspects. If someone claims ISO C compliance for a commercial product, but radically deviates from ISO 9899 despite their claim, then they could of course end up in a lawsuit. Furthermore, there are things like safety Directives (law) pointing at technical standards and your product is regarded as conforming to the Directive only if you fulfil the standards. There are such standards (for functional safety, machinery etc) in turn listing ISO 9899 as a normative reference. – Lundin Feb 11 '22 at 07:35
  • As for gcc, it is non-profit and probably never claimed any form of suitability for safety-related software, so they wouldn't be affected. But a commercial company like Wind River, specializing in such compilers, could be. – Lundin Feb 11 '22 at 07:38
  • @Lundin: ISO C and C are different entities, and ISO has no more authority over or claim against a vendor offering a C implementation without calling it an ISO C implementation than Smucker’s has over a vendor offering peanut butter without calling it Smucker’s peanut butter. – Eric Postpischil Feb 11 '22 at 13:00

3 Answers3

4

We have long + int * unsigned.

The * expression will be unsigned. The reason is that int and unsigned have the same conversion rank, and the unsigned type wins: the signed operand is converted to unsigned, and the multiplication is between two unsigned, its result being of that type.

Thus, the addition is then long + unsigned. Here things get tricky. If the implementation's long can represent all of the values of unsigned, then the unsigned will be converted to long; the addition is of two long operands and the result is long. But if unsigned has values outside of the long range (e.g. 32 bit unsigned and 32 bit long), then both operands will convert to unsigned long and the addition will be in that type.

In other words, the type ends up being platform-specific, depending on the relative range of unsigned and long.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • Rather, the `long` operand and the `unsigned int` both get converted to `unsigned long`, in case both long and int are for example 32 bit. – Lundin Feb 10 '22 at 08:29
  • 1
    Yes, the promotion is determined by the last paragraph in **6.3.1.8** *Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.* You should quote the C Standard to explain the promotion rules – chqrlie Feb 10 '22 at 08:30
  • @Lundin Ah, ok; this is the case which lands in the last paragraph: "Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type" since the unsigned type doesn't have a greater-or-equal rank versus the long, and has values outside of it. – Kaz Feb 10 '22 at 08:33
  • This really helped, thank you! – cdaly_ Feb 10 '22 at 21:38
1

Check out Implicit type promotion rules. Then use that together with operator precedence to figure out how which operands that bind to each other - type promotion will be per sub expression, then the resulting type of each sub expression becomes the operand for the next.

Multiplication naturally has higher precedence than addition and casts have higher precedence still, so the expression is equivalent to this:

((long)i) + ( ((int)j) * k )

In the subexpression inside the parenthesis, there's an explicit conversion of j to int, then the usual arithmetic conversions as per the above link determines the type used for that subexpression. It also becomes the resulting type used when determining what type to use for the addition. Once again, it's the usual arithmetic conversions.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

Other answers are telling you how to figure out the type using the C standard, but if you just want to know what the answer is for your particular compiler and compiler settings, then try compiling this invalid code:

int i;
long j;
unsigned int k;

void foo()
{
  char * x = (long) i + (int) j * k;
}

You will get a warning that says something like:

warning: initialization of 'char *' from 'long int' makes pointer from integer without a cast [-Wint-conversion]

This error message reveals to us that the compiler has decided that the type on the right-hand side of the assignment is a long int.

David Grayson
  • 84,103
  • 24
  • 152
  • 189
  • One *might* get such a warning. Or one might not. Compilers are not consistent about what warnings they emit under what circumstances, not even across different versions of the same compiler. – John Bollinger Feb 10 '22 at 17:01
  • OK. I'd like to know if anyone finds a particular compiler where modern versions of it don't print a useful warning/error like this. Possibly we could make it print an error more reliably by making the code less valid, like maybe `x` should be a struct. – David Grayson Feb 10 '22 at 18:13
  • @JohnBollinger The compiler is _required_ to omit a diagnostic message here since the code is a constraint violation. It is however not required to give any meaningful type information. – Lundin Feb 11 '22 at 07:25
  • 1
    A more reliable way would however be `#define print_type(expr) _Generic((expr), long: puts("long"), unsigned long: puts("unsigned long"));` ... `print_type((long) i + (int) j * k);` – Lundin Feb 11 '22 at 07:26
  • Yes, @Lundin, it is a constraint violation, and conforming compilers must therefore diagnose it (details of the diagnostic unspecified). But there have been widely used, well regarded compilers that *by default* did not conform in that respect. – John Bollinger Feb 11 '22 at 13:19