Author Topic: Void cast as a function  (Read 6432 times)

0 Members and 1 Guest are viewing this topic.

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 2054
  • Country: us
Re: Void cast as a function
« Reply #25 on: August 02, 2017, 07:52:27 pm »
It's all about suppressing warnings. Back in the distant past it was surprisingly difficult to suppress the unused variable warning without actually generating any code. So people came up with nonsense like this. It does nothing, just ignore it.
These days compilers are smart enough to handle more obvious ways of suppressing the warning. Or you just don't name the argument and that avoids the warning.
True, still compilers today are so smart they throw away unused strings of for instance program version information.
I always add a string at the start of my code with the ProductName, SVN commitnr, Date and compiler version.
Why? Because when I read out a uC I can directly see if it is the correct code for the product and which version, it sometimes is a big timesaver.

When I don't use the pointer to that string somewhere in the code the compiler even in non-optimized mode will just throw it away, but then it is not a great compiler :D
So something like this could also be used for that purpose.

Declare the string volatile const. Won't get thrown out then.

Yes it will, or at least it is allowed to.  Volatile guarantees that reads and writes to a variable will not be eliminated or reordered.  It does not prevent an unreferenced constant from being eliminated by the linker.
« Last Edit: August 03, 2017, 04:43:46 am by ejeffrey »
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 3404
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: Void cast as a function
« Reply #26 on: August 02, 2017, 09:43:56 pm »
Yes it will, or at least it is allowed to.  Volatile guarantees that reads and writes to a variable will not be eliminated or reordered.  It does not prevent an referenced constant from being eliminated by the linker.
This is the only correct answer. Volatiles will be read and/or written each expression.
You would need a storage duration specifier, like static or register. But even those are unsafe when the linker is cleaning unreferenced objects.
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: Void cast as a function
« Reply #27 on: August 03, 2017, 12:34:28 am »
Holy crap, programming since 1972 once I saw this prior post I
am leaving the programming profession.....


Quote
It would be perfectly legal C to say1

    (void (*)())(&y)();



I wish I had know about this site https://cdecl.org/ years ago, thanks grumpydoc.


Regards, Dana.
« Last Edit: August 03, 2017, 12:38:09 am by danadak »
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline Hypernova

  • Supporter
  • ****
  • Posts: 654
  • Country: tw
Re: Void cast as a function
« Reply #28 on: August 03, 2017, 04:45:29 am »
It would be perfectly legal C to say1

    (void (*)())(&y)();


It will also be perfectly legal for your team members to stone you to death if you try to put this in production code. The judge will surely acquit them.

It's done in the way it is in the op due to the code base being multi-platform, so you can't rely on a common compiler command to flag it as unused.
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3056
  • Country: fr
Re: Void cast as a function
« Reply #29 on: August 03, 2017, 09:49:24 am »
anyone still uses that?

emm, you are supposing that people can always use gcc/llvm.
In Avionics we can't. But, of course, we have a similar tool.

My bad, you are right, of course. I was looking at it through the prism of a software guy where tools like Lint have been largely rendered unnecessary by the compilers getting better, rendering linting largely redundant. Embedded dev and fields where special vendor toolchains are needed are a different matter, those compilers can really compile all sorts of dangerous crap without a peep of a warning.
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3056
  • Country: fr
Re: Void cast as a function
« Reply #30 on: August 03, 2017, 09:53:23 am »
IMO it is worse to use these kind of "bogus" compiler satisfying code then to disable a certain warning for Lint around the cause, so if one line throws a warning put a disable and re-enable around it with in the comments the reason why you disabled the Lint warning for that line. At least any following programmer will understand what has been done and why.

That isn't always an option. And littering the code with stuff like (Visual Studio):
#pragma warning( push )
#pragma warning( disable : 4101)
// Your function
#pragma warning( pop )

+ comment explaining which warning is being suppressed is not really more readable vs that one liner. The comment explaining the construct probably would be still a good idea.

 

Offline grumpydoc

  • Super Contributor
  • ***
  • Posts: 2701
  • Country: gb
Re: Void cast as a function
« Reply #31 on: August 03, 2017, 10:52:10 am »
It will also be perfectly legal for your team members to stone you to death if you try to put this in production code. The judge will surely acquit them.
Typedef is your friend :)

Quote
It's done in the way it is in the op due to the code base being multi-platform, so you can't rely on a common compiler command to flag it as unused.
It's still an ugly hack whatever the excuse.

 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 2054
  • Country: us
Re: Void cast as a function
« Reply #32 on: August 04, 2017, 02:55:03 am »

But C generally makes no distinction between a data address and a function address - anything which can be cast to a function pointer type can be used to call a function.

It would be perfectly legal C to say1

    (void (*)())(&y)();


This is pretty far off topic, but not really.  Casting between function and data pointers is not defined in C in any useful way.  The compiler will let you do it because it might work on your some platforms. Even by the standards of C's weak guarantees on the behavior of casts, converting between function and data pointers is fraught with peril. 

Code and data pointers don't have to be part of the same address space.  You could be on a harvard architecture, you could have segmentation, and even on modern architectures that don't have those problems, it is possible that virtual memory protection will prevent you from executing from a data region or reading from a code region.  Furthermore, some architectures poke extra bits into function pointers.  Some 64 bit systems put extra bits in the otherwise unused high bits to mitigate stack overflows. ARM uses the low bit to determine whether the target is a arm or thumb instruction set.  So even things that look like they should work will not.  For instance, if you know the physical address of a function, store it as an integer, then cast to a function pointer and call it, you will get a fault on an ARM Cortex because it only supports the thumb instruction set and needs the low order bit to be one.  Likewise, if you try to convert a function pointer to a void * and memcpy it that would fail for the same reason.  Function and data pointers don't even have to be the same size: back in the DOS days, you could use a memory model where data used far pointers and code used near pointers (or vice versa).  In this case, even something innocuous like casting a function pointer to void* and back may lose information and fail.  All C guarantees is that you can cast a function pointer to another type and back losslessly.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 1946
  • Country: ca
Re: Void cast as a function
« Reply #33 on: August 04, 2017, 03:24:51 am »
Casting between function and data pointers is not defined in C in any useful way.  The compiler will let you do it because it might work on your some platforms.

That is true, but it might be useful - for example you can generate code and then execute it. Of course it'll be platform dependent, but still ...
 

Online orin

  • Frequent Contributor
  • **
  • Posts: 444
  • Country: us
Re: Void cast as a function
« Reply #34 on: August 04, 2017, 04:17:41 am »
IMO it is worse to use these kind of "bogus" compiler satisfying code then to disable a certain warning for Lint around the cause, so if one line throws a warning put a disable and re-enable around it with in the comments the reason why you disabled the Lint warning for that line. At least any following programmer will understand what has been done and why.

That isn't always an option. And littering the code with stuff like (Visual Studio):
#pragma warning( push )
#pragma warning( disable : 4101)
// Your function
#pragma warning( pop )

+ comment explaining which warning is being suppressed is not really more readable vs that one liner. The comment explaining the construct probably would be still a good idea.


The Microsoft compilers also have

#pragma warning(suppress: 4101)

which disables 4101 for the next line only.  Though you have to put it the line before the line where compiler detects the warning... which might not be the line you think.

It's not too bad.  I always turn _all_ warnings on and insist on at least _understanding_ them before disabling or suppressing them.  Probably less than one in one hundred of such warnings is 'real', but reviewing a hundred or so warnings takes much less time than tracking down that mystery bug...
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3056
  • Country: fr
Re: Void cast as a function
« Reply #35 on: August 04, 2017, 04:46:34 pm »
IMO it is worse to use these kind of "bogus" compiler satisfying code then to disable a certain warning for Lint around the cause, so if one line throws a warning put a disable and re-enable around it with in the comments the reason why you disabled the Lint warning for that line. At least any following programmer will understand what has been done and why.

That isn't always an option. And littering the code with stuff like (Visual Studio):
#pragma warning( push )
#pragma warning( disable : 4101)
// Your function
#pragma warning( pop )

+ comment explaining which warning is being suppressed is not really more readable vs that one liner. The comment explaining the construct probably would be still a good idea.


The Microsoft compilers also have

#pragma warning(suppress: 4101)

which disables 4101 for the next line only.  Though you have to put it the line before the line where compiler detects the warning... which might not be the line you think.

It's not too bad.  I always turn _all_ warnings on and insist on at least _understanding_ them before disabling or suppressing them.  Probably less than one in one hundred of such warnings is 'real', but reviewing a hundred or so warnings takes much less time than tracking down that mystery bug...

Suppress is actually a fairly bad idea that could give you some nasty surprises, especially if the code contains macros or you are trying to write portable code:

https://visualstudio.uservoice.com/forums/121579-visual-studio-ide/suggestions/2339300--pragma-warning-suppress-should-operate-on-the-ne
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3056
  • Country: fr
Re: Void cast as a function
« Reply #36 on: August 04, 2017, 04:51:51 pm »
Casting between function and data pointers is not defined in C in any useful way.  The compiler will let you do it because it might work on your some platforms.

That is true, but it might be useful - for example you can generate code and then execute it. Of course it'll be platform dependent, but still ...

That is a sure fire way to have the program blow up in your face on any platform that blocks execution from data segments. Like 'NX' bit on Intel, ARM has now a similar flag too. And, of course, any Harward-style platform.

Please, don't do this. There are extremely few situations where this sort of hack should be required. Even if you are implementing something like a JIT there are proper ways to do it that don't require such casts.
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 5779
  • Country: nl
Re: Void cast as a function
« Reply #37 on: August 04, 2017, 05:17:00 pm »
Suppress is actually a fairly bad idea that could give you some nasty surprises, especially if the code contains macros or you are trying to write portable code:

It depends on the alternatives. There is no Utopia where all warnings esp from Lint can be solved in a nice clean way.
If your coding guidelines do not allow warnings you have little choice.

Another alternative to leave hundreds of warnings than chance is high  you will never notice any new serious warning.
So yeah although I agree in principle, the hard reality and possible choices do not always go hand in hand with studybook theory.
 
The following users thanked this post: jancumps

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3056
  • Country: fr
Re: Void cast as a function
« Reply #38 on: August 04, 2017, 10:24:44 pm »
Suppress is actually a fairly bad idea that could give you some nasty surprises, especially if the code contains macros or you are trying to write portable code:

It depends on the alternatives. There is no Utopia where all warnings esp from Lint can be solved in a nice clean way.
If your coding guidelines do not allow warnings you have little choice.

Another alternative to leave hundreds of warnings than chance is high  you will never notice any new serious warning.
So yeah although I agree in principle, the hard reality and possible choices do not always go hand in hand with studybook theory.

You have misunderstood me. Warnings certainly need to be fixed or silenced if spurious.

However using the suppress pragma in Visual Studio is not the best method of doing that and will not even work if you use #ifdef/#endif macros to provide support for more than one compiler. In that case I find that dummy cast to void pointer a lesser evil - no messy #ifdefs are needed, no need to push/pop warning settings neither, the entire thing is one line. Maybe put a comment next to it explaining that it is to suppress a spurious warning in case someone wonders. It is much more readable.
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 5779
  • Country: nl
Re: Void cast as a function
« Reply #39 on: August 05, 2017, 09:14:29 am »
How about the hundreds of other possible warnings Lint can produce?
Are you going to write inline code for those too?  :-//

If you use a tool and that tool has some unwanted side effects and the tool has an option built in to circumvent that side effect, i say use it or use a different tool.
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3056
  • Country: fr
Re: Void cast as a function
« Reply #40 on: August 05, 2017, 09:46:25 am »
How about the hundreds of other possible warnings Lint can produce?
Are you going to write inline code for those too?  :-//

If you use a tool and that tool has some unwanted side effects and the tool has an option built in to circumvent that side effect, i say use it or use a different tool.

If you are using an actual Lint, that one has a configuration file to suppress warnings. And for any normal codebase with reasonably set up tooling suppressing warnings is an exception, not a rule.

And yes, if a certain warning has to stay on, I am totally happy to write a (commented) cryptic oneliner to avoid a spurious warning than to spew something like this all over the codebase whenever there is one:

#ifdef _MSC_VER
#pragma warnings (push)
#pragma warning(disable:XXXX)
#endif

#ifdef __GNUC__
// do something to disable the warning in GCC
#endif

#ifdef __clang__
// do something for Clang
#endif

the offending line of code here;

#ifdef _MSC_VER
#pragma warning (pop)
#endif

#ifdef __GNUC__
// restore the GCC warning
#endif

#ifdef __clang__
// restore the Clang warning
#endif

....

And this handles only Visual C++, GCC and Clang - all very common if you are building for Windows (MSVC + GCC), Mac (Clang) and Linux (GCC+Clang). Wonderfully readable code, isn't it?

Once you have to deal with this, you will start to appreciate those one-liners, especially for stupid stuff like unused function arguments or local variables.

« Last Edit: August 05, 2017, 09:55:32 am by janoc »
 

Online orin

  • Frequent Contributor
  • **
  • Posts: 444
  • Country: us
Re: Void cast as a function
« Reply #41 on: August 05, 2017, 08:27:15 pm »
Don't forget the existence of #elif.

#if defined(_MSC_VER)
// MSC stuff
#elif defined(__GNUC__)
// GNU stuff
#elif defined(__clang__)
// clang stuff
#endif

 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 5779
  • Country: nl
Re: Void cast as a function
« Reply #42 on: August 05, 2017, 10:21:43 pm »
Quote
And yes, if a certain warning has to stay on, I am totally happy to write a (commented) cryptic oneliner to avoid a spurious warning than to spew something like this all over the codebase whenever there is one:
Ah yes  in that case it is insane, we only have a single c compiler and a lint disable and re-enable is each one comment line so that is not as bad. To each its own.
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3056
  • Country: fr
Re: Void cast as a function
« Reply #43 on: August 07, 2017, 11:37:15 am »
Don't forget the existence of #elif.

#if defined(_MSC_VER)
// MSC stuff
#elif defined(__GNUC__)
// GNU stuff
#elif defined(__clang__)
// clang stuff
#endif

Yay, way to miss the point ...  :palm:
 

Online orin

  • Frequent Contributor
  • **
  • Posts: 444
  • Country: us
Re: Void cast as a function
« Reply #44 on: August 07, 2017, 05:09:58 pm »
Don't forget the existence of #elif.

#if defined(_MSC_VER)
// MSC stuff
#elif defined(__GNUC__)
// GNU stuff
#elif defined(__clang__)
// clang stuff
#endif

Yay, way to miss the point ...  :palm:


No, I didn't miss the point.  I merely pointed out a less verbose method of handling _anything_ that's compiler dependent.

Nothing says that the 'tricks' presented work on all compilers and wouldn't necessitate an #if ... #endif stream somewhere.  The unused variable problem is better solved in other ways - like not declaring a local variable you aren't going to use or not naming unused function parameters or a compiler dependent UNUSED(x) macro.

 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3056
  • Country: fr
Re: Void cast as a function
« Reply #45 on: August 09, 2017, 06:30:04 pm »

No, I didn't miss the point.  I merely pointed out a less verbose method of handling _anything_ that's compiler dependent.

Nothing says that the 'tricks' presented work on all compilers and wouldn't necessitate an #if ... #endif stream somewhere.  The unused variable problem is better solved in other ways - like not declaring a local variable you aren't going to use or not naming unused function parameters or a compiler dependent UNUSED(x) macro.

The unused function arguments or local variables usually arise in situations when there is a defined interface and there are several variants of the code implementing it, either configuration or machine dependent. So not declaring them may not be an option, the same as not naming unused function parameters - they could be used in another build variant or the naming even mandated by a code style policy (very likely, given that we are talking an environment where these warnings have to be enabled in the first place).

Your idea with the #if/#elif/... chain is less verbose however, it is more problematic from the code management point of view. It saves a few lines at the expense of risking merge errors (e.g. when using source revision control), whenever a new supported architecture is being added. Each addition necessitates changing the last #endif to #elif, risking introducing build errors. The #ifdef/#endif pairs are more self contained, that's why you will see these more often.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf