Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
JawnV6
Jul 4, 2004

So hot ...
wanna mark this thread __attribute__((noreturn))

Adbot
ADBOT LOVES YOU

vOv
Feb 8, 2014

Does this function have any missing returns?

code:
int f() {
  somethingThatMightHalt();
}
Obviously you can check for missing returns just by looking at code flow analysis, I'm just saying you're going to get some false positives.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
c# will complain if a path through a non-void method exists that reaches the end without returning/throwing/etc. Sometimes it gets things wrong - for example, this doesn't compile:

code:
// fails compilation with CS0161 "not all code paths return a value"
static bool X (bool y)
{
    switch (y)
    {
        case true: return true;
        case false: return false;
    }
}
but I think that's still better than the opposite failure mode of allowing something through that shouldn't be allowed.

Jeb Bush 2012
Apr 4, 2007

A mathematician, like a painter or poet, is a maker of patterns. If his patterns are more permanent than theirs, it is because they are made with ideas.

HappyHippo posted:

It's not really a halting problem issue. Which is why other languages can easily handle this and enforce the rule that all code paths that return actually return a value.

vOv is right that the problem does reduce from the halting problem (as does the problem of finding unused code paths more generally), and so getting around it requires accepting some false positives, which is what "the last statement must be a return" does

it comes down to how much value you put on allowing code like the example Xarn mentions. I personally can't see any problem with automatically inserting an error statement at the end of any (non-main) function without a return, but maybe it causes some problem that's not occurring to me right now?

Xarn
Jun 26, 2015
It is a philosophy thing, just like why std::vector::operator[] is not range checked.

C generally errs wayyy too much on the side of trusting the programmer, including in this. so it is assumed that if there is no return statement, then that means the programmer knows we cannot hit this path through function. Other languages (definitely at least Java and C#) err on the side of not trusting the programmer, so if it cannot absolutely, 100% guaranteed, prove that the path with no return statement is not taken, then it tells the programmer to gently caress off and provide return statement (or a call to noreturn declared function).

dwazegek
Feb 11, 2005

WE CAN USE THIS :byodood:

Hammerite posted:

c# will complain if a path through a non-void method exists that reaches the end without returning/throwing/etc. Sometimes it gets things wrong - for example, this doesn't compile:

code:
// fails compilation with CS0161 "not all code paths return a value"
static bool X (bool y)
{
    switch (y)
    {
        case true: return true;
        case false: return false;
    }
}
but I think that's still better than the opposite failure mode of allowing something through that shouldn't be allowed.

code:
public static void DoStuff()
{
    switch (Blah())
    {
        case false:
            Console.WriteLine("false");
            break;
        case true:
            Console.WriteLine("true");
            break;
        default:
            Console.WriteLine("huh?");
            break;

    }
}

private static unsafe bool Blah()
{
    byte b = 2;
    void* bPtr = &b;
    return *((bool*)bPtr);
}
A coding horror? Perhaps. As far as I know this issue only crops up when switching on bools though. So just never do that.

Jeb Bush 2012
Apr 4, 2007

A mathematician, like a painter or poet, is a maker of patterns. If his patterns are more permanent than theirs, it is because they are made with ideas.

Xarn posted:

It is a philosophy thing, just like why std::vector::operator[] is not range checked.

C generally errs wayyy too much on the side of trusting the programmer, including in this. so it is assumed that if there is no return statement, then that means the programmer knows we cannot hit this path through function. Other languages (definitely at least Java and C#) err on the side of not trusting the programmer, so if it cannot absolutely, 100% guaranteed, prove that the path with no return statement is not taken, then it tells the programmer to gently caress off and provide return statement (or a call to noreturn declared function).

but refusing to do range checks is about performance. what would be the issue with calling abort on reaching the end of a function without a return, instead of returning garbage? it doesn't add any extra work for the programmer, and in the case where the programmer is right would make absolutely no difference (besides a tiny increase in executable size)

Jeb Bush 2012 fucked around with this message at 21:26 on Mar 5, 2018

vOv
Feb 8, 2014

I could see a 'nice' compiler doing it at -O0 just as a convenience thing since it's undefined behavior.

Bongo Bill
Jan 17, 2012

Xarn posted:

It is a philosophy thing, just like why std::vector::operator[] is not range checked.

C generally errs wayyy too much on the side of trusting the programmer, including in this. so it is assumed that if there is no return statement, then that means the programmer knows we cannot hit this path through function. Other languages (definitely at least Java and C#) err on the side of not trusting the programmer, so if it cannot absolutely, 100% guaranteed, prove that the path with no return statement is not taken, then it tells the programmer to gently caress off and provide return statement (or a call to noreturn declared function).

As a programmer, it is my earnest belief that I should not be trusted

Xarn
Jun 26, 2015

Bongo Bill posted:

As a programmer, it is my earnest belief that I should not be trusted

:same: thats why all of my C++ code uses all the warnings and enables Werror :v:

Spatial
Nov 15, 2007

Jeb Bush 2012 posted:

but refusing to do range checks is about performance. what would be the issue with calling abort on reaching the end of a function without a return, instead of returning garbage? it doesn't add any extra work for the programmer, and in the case where the programmer is right would make absolutely no difference (besides a tiny increase in executable size)
Code size affects performance. :v:

Jeb Bush 2012
Apr 4, 2007

A mathematician, like a painter or poet, is a maker of patterns. If his patterns are more permanent than theirs, it is because they are made with ideas.

Spatial posted:

Code size affects performance. :v:

no poo poo. the question is, would the resulting increase in code size represent a non-negligible performance issue? we're talking about inserting one function call into a fairly small subset of functions

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?
c/c++ is all about having undefined behavior that trips everyone up and causes thousands of bugs so that the complier writers can eke out tiny performance increases.

Spatial
Nov 15, 2007

That's the reason you'll be given for why it's not done.

In reality this isn't an issue, this is something nerds like to argue about on the internet. The defacto standard is to warn when not all control flow paths return, even the crappy embedded compilers do it.

This is the ideal situation for braindamaged C lovers: no overhead at all, while still maximising opportunities to snidely talk down to others about their unawareness of undefined behaviour

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?
Just tried it in whatever version of gcc is on my work machine and got no warning at all.

Spatial
Nov 15, 2007

HappyHippo posted:

Just tried it in whatever version of gcc is on my work machine and got no warning at all.
That's bad. I don't use GCC, but normall ypeople do enable warnings right?

Xarn
Jun 26, 2015

HappyHippo posted:

Just tried it in whatever version of gcc is on my work machine and got no warning at all.

Yeah, this is the second really hosed up part of gcc: it has essentially no warnings on by default, and even -Wall -Wextra is a small subset of what it can tell you.

What I am saying is, screw gcc, use clang. :colbert:

Jeb Bush 2012 posted:

no poo poo. the question is, would the resulting increase in code size represent a non-negligible performance issue? we're talking about inserting one function call into a fairly small subset of functions

If you want honest answer, then it doesn't until it does :v: Essentially as long your hot loops fit into icache, their size being different tends to have only marginal effect*. But once you no longer fit, the perf hit is pretty drastic.


* If you are doing e.g. high-end matrix multiplication, you can tell difference of every single superfluous instruction. But that is the sort of code that will not have trouble with missing return values.

JawnV6
Jul 4, 2004

So hot ...

HappyHippo posted:

Just tried it in whatever version of gcc is on my work machine and got no warning at all.
I understood the bar to be a bit higher than this:

Spatial posted:

even the crappy embedded compilers do it.

FlapYoJacks
Feb 12, 2009
If you compile with -Wreturn-type it will bitch at you.

Really you should be compiling with -Wall -Werror anyways, but yeah, gcc should bitch by default.

Spatial
Nov 15, 2007

A couple of days ago I came across this line which made me double-take:
C++ code:
*(volatile unsigned int*)(0x28000000 | ((3<<4 | 2) << 13);
What does this do? This is from an embedded system. It talks to an SDRAM chip via the address pins. The magic numbers "(3<<4 | 2)" are the operating mode: CAS latency 3, bursts of 4. I still don't know what the shift by 13 does since there are only 15 address pins, but it doesn't work if the shift is not there.

Qwertycoatl
Dec 31, 2008

Spatial posted:

A couple of days ago I came across this line which made me double-take:
C++ code:
*(volatile unsigned int*)(0x28000000 | ((3<<4 | 2) << 13);
What does this do? This is from an embedded system. It talks to an SDRAM chip via the address pins. The magic numbers "(3<<4 | 2)" are the operating mode: CAS latency 3, bursts of 4. I still don't know what the shift by 13 does since there are only 15 address pins, but it doesn't work if the shift is not there.

Today I had to fix a bug that turned out to be something reading a register via a hardcoded address like that, but using the address that would have been correct in a previous generation of the product.

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

Spatial posted:

A couple of days ago I came across this line which made me double-take:
C++ code:
*(volatile unsigned int*)(0x28000000 | ((3<<4 | 2) << 13);

Oh look, a legitimate use of volatile. Never thought I'd see one

Spatial
Nov 15, 2007

I read the datasheet for the microcontroller, the memory controller, and the memory module and I still have no idea where the hell that "<<13" came from or why it does anything. :(

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

JawnV6 posted:

wanna mark this thread __attribute__((noreturn))

csammis
Aug 26, 2003

Mental Institution

Spatial posted:

A couple of days ago I came across this line which made me double-take:
C++ code:
*(volatile unsigned int*)(0x28000000 | ((3<<4 | 2) << 13);
What does this do? This is from an embedded system. It talks to an SDRAM chip via the address pins. The magic numbers "(3<<4 | 2)" are the operating mode: CAS latency 3, bursts of 4. I still don't know what the shift by 13 does since there are only 15 address pins, but it doesn't work if the shift is not there.

It works out to 0x28064000...is that address aliased to a region that maps to the SDRAM with those specific parameters? :psyduck:

edit:

Jabor posted:

Are you sure it's 3 and 4 that are the parameters there? I would have thought that it's the 3 and 2, and the shift by 4 is to put the 3 in the right bits.

I would think that too but I also wouldn't think that an MCU would do what I suggested above anyway. The parts I've worked with have discrete modes for setting the timing parameters prior to reading and writing.

csammis fucked around with this message at 03:06 on Mar 6, 2018

VikingofRock
Aug 24, 2008




hackbunny posted:

Oh look, a legitimate use of volatile. Never thought I'd see one

volatile is for hardware registers that might have their value changed by something other than your code, right?

Phobeste
Apr 9, 2006

never, like, count out Touchdown Tom, man

csammis posted:

It works out to 0x28064000...is that address aliased to a region that maps to the SDRAM with those specific parameters? :psyduck:

Yeah usually peripherals in embedded systems, or well pretty much any system to be honest it's just hidden are mapped somewhere in physical memory. it's either that or designated instructions.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Are you sure it's 3 and 4 that are the parameters there? I would have thought that it's the 3 and 2, and the shift by 4 is to put the 3 in the right bits.

qsvui
Aug 23, 2003
some crazy thing

JawnV6 posted:

wanna mark this thread __attribute__((noreturn))

You'll be glad to know that this attribute is standard in C++11 as [[noreturn]].

The Phlegmatist
Nov 24, 2003

VikingofRock posted:

volatile is for hardware registers that might have their value changed by something other than your code, right?

Yes, it prevents certain compiler optimizations like loading the value from memory, storing it in a register and never checking the actual memory address again when the compiler deduces that your code does not change the variable.

The problem was people trying to use it for multithreading, which doesn't work except on, like...IA64? There's no guarantee of atomicity provided by volatile in C and C++.

Spatial
Nov 15, 2007

csammis posted:

It works out to 0x28064000...is that address aliased to a region that maps to the SDRAM with those specific parameters? :psyduck:

I would think that too but I also wouldn't think that an MCU would do what I suggested above anyway. The parts I've worked with have discrete modes for setting the timing parameters prior to reading and writing.
The MCU does have a bunch of registers for setting the memory controller timing. This read happens after all that setup and it's used to configure the actual SDRAM chip.

Before that read happens, the memory controller is instructed to put the SDRAM into the "load mode register" state so it can be configured. This register must be written via the address pins of the SDRAM chip. The only way to do that is to make the memory controller issue a read so that it puts the appropriate values on the address pins. Hence the crazy code.

Jabor posted:

Are you sure it's 3 and 4 that are the parameters there? I would have thought that it's the 3 and 2, and the shift by 4 is to put the 3 in the right bits.
I was being a bit vague there. The burst size parameter means 4, but it's specified as a power of 2 hence the value 2.

QuarkJets
Sep 8, 2008

Man I guess Marvel movies have gotten really weird

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

The Phlegmatist posted:

The problem was people trying to use it for multithreading, which doesn't work except on, like...IA64? There's no guarantee of atomicity provided by volatile in C and C++.

It's complicated!

volatile forces the compiler to emit the exact access requested in the exact order requested. You are right that there technically aren't any requirements about how the access is performed, but in practice there's a handshake agreement that volatile accesses will be implemented in an "obvious" way, i.e. with an appropriate single load/store instruction (or addressing mode where applicable). Most architectures do guarantee that aligned loads and stores will be atomic, in the basic sense that such loads will never observe partial results from such stores. So in practice you can get a certain level of atomicity from volatile accesses. And the compiler is required to assume that the access might be weird in unspecifiable ways; e.g. if there are two immediately-consecutive volatile loads from the same variable, the compiler not only has to perform both loads, but it has to assume that they might have read different values; that's also somewhat useful.

What you do not get is even the slightest statement about memory ordering. Volatile accesses do not synchronize with other threads on any level. On processors with weak memory ordering (like ARM or PowerPC), reading a value from a volatile variable is not sufficient at a hardware level to ensure that subsequent loads will see the result of stores that occurred before the store that put that value there. Even on processors with stronger ordering at the hardware level (like x86 and x86-64), nothing stops the compiler from reordering non-volatile accesses around volatile ones. It is almost always the case that such memory ordering is necessary for correctness, and even if it isn't, there's no real guarantee that the compiler will honor that handshake agreement about emitting your access in an obvious way. So people rightly tell you to never use volatile for threads.

redleader
Aug 18, 2005

Engage according to operational parameters

rjmccall posted:

...in practice there's a handshake agreement that volatile accesses will be implemented in an "obvious" way...

Is this one of those rare scenarios where C/C++ compiler writers don't call their language lawyers and go for maxxximum performance by stretching the specification nearly to breaking point?

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
Even a malevolently-correct volatile implementation would prevent most of the optimizations which break incorrect code, since the whole point is to force the compiler to emit code which it can "prove" is unnecessary.

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

VikingofRock posted:

volatile is for hardware registers that might have their value changed by something other than your code, right?

Hardware registers do more than that: you are not expected to "read back" the values you "wrote". Each address in a range of memory mapped registers is, essentially, a function declaration, and each read or write a function call. volatile pretty much turns memory accesses into function calls. Kinda

Rubellavator
Aug 16, 2007

A few months ago I solved an issue by throwing the volatile keyword at some Java code in idiotic fashion. I remembered it as "the thing that really makes the variable read the proper value when it isn't" from some C I wrote for a microprocessors class in college. Multiple threads and a status flag. Strange thing is the code would work in a debugger if you set a breakpoint in the right spot. The volatile keyword in Java tells threads to hit main memory instead of checking local thread cache, a thing that I wasn't even aware of. So the status flag would get set and the other thread would just never see the update because it was checking against its cache.

Carbon dioxide
Oct 9, 2012

I don't know about C, but in Java it's simple. If you got any sort of variable that's being accessed by multiple threads, slap volatile on it.

E: Or use the synchronized keyword on the accessing methods in a sensible manner.

On the other hand, if you NEED the volatile keyword at all, it might be time to take a step back and rethink your code's architecture. Ideally you use multithreading to split up the code in such a way that the parts never need to interact again, except perhaps at the end where you synchronously wait for everything to finish. I think such a design should be possible in any program that doesn't need very high performance.

Anyway, I came here to post this:
https://everythingfunctional.wordpress.com/2018/03/07/haskelly-fizzbuzz/

Gotta love the way functional programmers think.

Carbon dioxide fucked around with this message at 07:56 on Mar 7, 2018

chippy
Aug 16, 2006

OK I DON'T GET IT
I just found this line of C# to check that two ints (noDetails, noPictures) are equal. it took me a second to even parse it's purpose.

code:
var areEqual = new[] { noDetails, noPictures }.Distinct().Count() == 1;

Adbot
ADBOT LOVES YOU

Maw
Feb 18, 2013

Mere minutes after discovering the new technology, it was used to send me a crude ASCII dong.


chippy posted:

I just found this line of C# to check that two ints (noDetails, noPictures) are equal. it took me a second to even parse it's purpose.

code:
var areEqual = new[] { noDetails, noPictures }.Distinct().Count() == 1;

This is amazing

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply