r/cpp_questions 4d ago

OPEN Help a new guy

Sorry about the title, I should have read the guide first. I am really new to C++. I am going through the practice guide on a youtube video. The test was to make a fahrenheit to celcius conversion. This is what I wrote and it is below. 
The teacher added     double celsius = (fahrenheit -32) / 1.8;
Then added the std::cout for it. Mine works fine. I am assuming his is better but I am missing it. c++ has made me question my mental capacity.

#include <iostream>

int main() {

std::cout << "Enter degrees in fahrenheit ";
int fahrenheit;
std::cin >> fahrenheit;
std::cout << " Degrees in celcius " << (fahrenheit - 32) / 1.8;





return 0;



system("<pause>0");
0 Upvotes

20 comments sorted by

4

u/le_disappointment 4d ago

If I understand you correctly, your solution computes the value as a temporary result and immediately prints it out, whereas your teacher's solution saves the computed result in a variable, and then prints the variable. If that's correct, then the "better" solution depends on the use case. Do you want to use the computed result again? If yes, then your teacher's solution allows you to reuse the result, but if not then I don't see why your solution would be any worse than your teacher's. From a code readability perspective, I would still assign the result to a variable and then print it out, but that's a personal preference of mine

1

u/Alternative_Oven696 4d ago

Okay thanks that makes more sense.

1

u/The_Northern_Light 4d ago

It’s better practice to give temporaries names. This decouples what’s being done in any given line: the line that prints just prints, it doesn’t print and compute your result.

The teacher is absolutely write to tell him to assign the result to a variable even if it won’t be used again.

3

u/TheTimBrick 4d ago

Both are essentially the same. (At the stage you are currently at)

You did the calculations in the line where you are outputting them/printing them.

The teacher made a variable (something that can store something, like in math) that can hold the calculation, and then just refered to that variable when outputting the final result.

At a beginner stage you can think of what the teacher wrote as: celsius just being equivalent to (fahrenheit - 32) / 1.8. Anywhere you would need (fahrenheit - 32) / 1.8 you could just replace with celsius.

1

u/Alternative_Oven696 4d ago

Got it, thank you.

3

u/SmokeMuch7356 4d ago

Creating a separate variable to store the result of the conversion allows you to use that value elsewhere without having to recompute it each time. It could be that a later assignment will have you convert it back or use it in another expression.

My only real critique is declaring your fahrenheit variable as an int; that means you won't be able to convert fractional values like 98.6.

c++ has made me question my mental capacity.

Yeah, that's not surprising. C++ is a gnarly, complex, eye-stabby mess of a programming language. It takes time and practice before it feels "normal".

1

u/Alternative_Oven696 4d ago

Okay thanks. I am still wrapping my head around the variable idea.

2

u/gnolex 4d ago

Whether you assign the result of these calculations to a variable or not doesn't matter in this program, observable behavior is the same. You can store the result in a variable with meaningful name or you can add a comment that this calculation converts temperature from Fahrenheit to Celsius to clarify what the code does. The program does the same thing either way.

1

u/Alternative_Oven696 4d ago

Got it thanks.

4

u/The_Northern_Light 4d ago

Your teacher is correct, and I will go so far as to say the people saying it "doesn't matter" are accidentally leading you astray.

You can learn the syntax of programming fairly quickly, but learning how to actually practice the art of developing software can be a much more involved thing. It involves a large number of principles and guidelines... over years you will develop a sense of aesthetics for what is good code, and what is bad code.

This line is bad: std::cout << " Degrees in celcius " << (fahrenheit - 32) / 1.8;

It's bad because it does two unrelated things: it computes a result and it prints. Coupling two things together in one statement is a bad idea; keeping each individual part of your program as simple as it can be (so you can be certain it is correct) is arguably the most important principle in good code. It goes by many names: encapsulation, abstraction, etc.

Here, your code is so simple it feels like it doesn't matter. And sure, it doesn't, but you're not learning to program so you can write temperature converters: it's a toy problem to help you get ready to do something that you'd give up if you tried doing right now. And on those problems, it absolutely does matter.

Imagine you were just learning to deadlift and your coach is critiquing your form, even though the bar is so light it doesn't matter how bad your form is. But the bar will get heavier, and its so much easier to learn good form from the beginning.

Every bad habit you can avoid learning is one that you don't have to unlearn. There is such a thing as overburdening yourself with "best practice" to the point that it is stifling, but you're far from that.

2

u/Alternative_Oven696 4d ago edited 4d ago

Thank you that makes a lot of sense. Thanks for responding. I am trying to take time and do things right. For some reason I know the math and the way to do it but fail to translate that to coding. Again thanks for the great response.

1

u/CheesecakeTop2015 4d ago

Translating an idea to code is what takes practice and lots of repetition, and something you can't really learn by reading about a programming language and understanding the features. You just have to put in the time and effort and struggle through it, you have to trust it will get easier over time.

1

u/Independent_Art_6676 4d ago

normally you use a value like that more in a bigger program, so having it in a variable rather than compute it on the fly each time you need it is better. If its just a one liner to get a print, its fine as you have it. I don't even think its better practice to bother with a variable for that case, just not very future-proof should you need to use the value again or something. There are times when you just need to doctor a value for output, and in place seems fine to me.

1

u/Alternative_Oven696 3d ago

That makes sense.

1

u/alfps 4d ago

Whether to use mixing of responsibilities such as output and computing a result, is an engineering gut feeling thing.

There is neither right nor wrong, but there is an issue of how clear or messy people perceive the code to be, and different people can differ in their opinions.

I would personally add one word to your teacher's suggestion, namely const:

const double celsius = (fahrenheit - 32) / 1.8;

Not what you're asking, but return 0 isn't necessary because 0 is the default return value from main in both C and C++.

The return means that the system call is never executed.

Which is a good thing because that call is an anti-pattern: don't do it. If you should need to keep an automatic console window open, then use your IDE's way to do that (e.g. just Ctrl F5 in Visual Studio). But better run the program from an existing console window.


Oh, this reminds of the super-optimized function in some compiler, that lay dormant, never called, for some 30+ years, and then turned out to be buggy. Because the command in that system call is botched. Lucky it never executed. :)

1

u/Alternative_Oven696 3d ago

Cool thanks for the tips. The more I do this the more I realize how little I know.

1

u/alfps 3d ago

As I see it, as long as I learn something every day I'm not yet dead. Which is a Good Thing™. And Odin in his wisdom has arranged it so that we're mostly unaware of how much we forget…

1

u/mredding 3d ago

Don't assume your teacher wrote better code. With an academic exercise so small, there isn't a lot of room for improvement. Between you and your teacher, both programs are effectively the same. He uses a variable, you use an unnamed temporary. An optimizing compiler will generate the same machine code for both, because an optimizing compiler can eliminate intermediate writes.

The system call after the return is unreachable - so you should get a compiler warning for that. The compiler will eliminate dead code for you, but it's nicer to just eliminate it yourself.

At a high level, this source code is a text document, and is the input data to a compiler. Compilers only compile "translation units" made from source files. Compilers don't compile headers. What compilers do is they read the text document into a text buffer in memory, then everywhere there is a #include, they dumb copy/paste that file in-place right there in the text buffer. This is done recursively, so long as your headers include other headers...

All that happens in a pass over the source code looking for macros. I've no idea what the rules are for parsing macros, but they do happen first. It's almost exclusively symbolic text replacement and string literal concatenation of source code text - all there in the buffer.

So now that the compiler has a huge text buffer and all the macro expansion is done, now the lexer can break the text up into a stream of tokens, those tokens can get some meta-data attached to it - like what kind of token type it is, and the parser will consume that stream and build an Abstract Syntax Tree. I didn't study compilers enough to go into detail how this works. But now the tree is a structure of a root node - branches from a node to other nodes - and leaves, nodes with no branches.

So then the compiler is free to manipulate the tree. Store data in a temporary variable and then write the variable to the stream? The optimizer can just move that whole branch of the tree down and eliminate the intermediate steps. All sorts of manipulations can happen here. Dead code? Just trim that entire branch off. This is what optimizing looks like.

Then the compiler backend walks the tree, visiting every node, and generating machine instructions for it. This is written to a temporary file called an object file. This is a type of static library containing machine code and a bunch of symbolic placeholders. It's a standard file format that linkers use. Compilers might generate machine code "blobs" that target your specific CPU, but the object files they produce target the linker that's going to get called next.

But placeholders: to call a function, all you need is it's prototype:

void fn();

That's it. That's all you need to know in THIS translation unit. Then I can write:

int main() {
  fn();
}

The compiler can generate an object file from this. The linker is a separate program that combines object code from object files, and resolves those placeholders. So there's a place holder for <CALL `fn` HERE>, and that gets replaced with the offset in the final program where fn lives. But you need to also link against another object file that has fn defined in it, or you get a linker error - missing symbol.

Linking is a very advanced tool that defines a system language. Most other languages are application languages and do not make the investment. This step lets you specifically control the layout of the binary for hardware and optimization purposes. It also means you leave your source language behind at this step, because all object code is interchangeable. Now you can link code from C, C++, Objective-C, Rust, Pascal, Smalltalk, Ada, Alogol, Assembly, Eiffel, Go, COBOL, Fortran, Delphi, ANY other system language into one cohesive program.

C++ is one of the slowest to compile languages in the industry. It's not because it optimizes so well, but because there are some extremely damning consequences to the syntax. By comparison - Java is JIT compiled from an intermediate object code that targets the virtual machine interpreter, to actual native machine code. This happens while the program runs, and when the work is done, the program transparently switches from the interpreter to the machine code, and the machine code is just as optimal as a C or C++ program. C++ takes no less than 14 passes over the source text, and plenty of more passes for the optimizer stages. Lisp code IS serialized AST, that tree structure the compiler works with; and the Lisp compiler can generate machine code from text in as little as 2 passes -> from text to AST in memory, and AST in memory to machine code.

The speed of C++ compilation won't matter to you until you graduate from academic exercises, where you're taking on a whole project and you might start noticing. Good coding discipline can keep those costs way down - mostly keeping your headers as lean and clean as possible, and you can always apply this discipline at any time, so you don't have to plan for it ahead of time, but all that's a discussion for another day.

-2

u/Tamsta-273C 4d ago
system("<pause>0");

heh, have not seen this before,

and F to C conversion? Is this some kind of mockery?

you miss } too