0

In code that is supposed to be quite portable, in a many person, many environment project, I have to deal with a problem with code that negates unsigned int (and same problem in other places negating std::size_t).

The intent is to create the additive inverse of that value (modulo MAX_VAL+1 where MAX_VAL is the max value of the type) and I found other questions on this topic confirm that is the standard specified behavior.

VS2012, (with compile time options I cannot easily learn) calls that line an error. The developer, with access to that environment, changed -U to -1*U, which compiles in that environment. I have a low opinion of that change and I'm not happy with the work I would need to go through to portability test that change to code that was correct in the first place.

I expect there is some #pragma, which will tell VS2012 to allow -U to have its standards defined meaning. I expect that will be easier to find than exploring any consequences of -1*U (beyond the fact that I think -1*U is disgusting).

But I'm hoping to get some language lawyer and/or VS2012 guru opinions before trying any of that.

Edit, I should have linked the relevant previous answer: What should happen to the negation of a size_t (i.e. `-sizeof(struct foo)`))?

I believe the original code is correct based on that answer. I want to know how to make VS2012 believe the code is correct.

The error message, is:

error C4146: unary minus operator applied to unsigned type, result still unsigned

Community
  • 1
  • 1
JSF
  • 5,281
  • 1
  • 13
  • 20
  • 3
    Unsigned is unsigned is unsigned. Did you mean using the `~` operator? – πάντα ῥεῖ Nov 09 '15 at 21:26
  • I certainly did not mean `~`. Please see the edit I added. Unsigned is unsigned but it also is something with a well defined and useful negation operator. – JSF Nov 09 '15 at 21:48
  • 1
    You need to actually post the code which gives the error, not just describe it. It seems unlikely that any compiler would reject `-U` so you need to provide some evidence for this claim. – M.M Nov 09 '15 at 21:54
  • @M.M, if your view is shared by a VS2012 expert (or if you are one) I guess I have a lot of work ahead of me before I could ask a better question (by which time I wouldn't need to). I can't even claim to disagree with your view. I just can't accuse a coworker of lying about this (and unfortunately I, not he, must follow up). So I hope some VS2012 guru contradicts you. The problem supposedly occurred in a bunch of places and nothing other than negating an unsigned was involved. – JSF Nov 09 '15 at 21:58
  • Can you post your code? Also, please explain the additive inverse concept – Shyamal Desai Nov 09 '15 at 22:00
  • No I can't post any code that will add anything. My best guess is some build-time options and not some code are what is relevant here anyway. The code really would be just `v=-u;` where both are previously declared as unsigned. So I need first to find what options in the compile command makes that an error and I don't have access to the compile command (in a project elsewhere in the company). "Additive inverse" means after doing the above `u+v==0` because `unsigned` is very well defined as modular arithmetic. – JSF Nov 09 '15 at 22:12
  • To clarify, I have access to all the source code involved, but the functions are too complicated to quote, even though the problem lines are trivial. I don't have access to the command line, so I can't test any guess at a minimal example. I was expecting this was something some VS2012 guru here would already know about. – JSF Nov 09 '15 at 22:17
  • @jsf _No I can't post any code that will add anything._ That's a ridiculous subterfuge. Of course you could provide a clarifying [MCVE]. Also it's obvious you'll need the next larger signed type (i.e. `signed long long`) to represent a _negated_ `unsigned int`. VTC now. – πάντα ῥεῖ Nov 09 '15 at 23:17
  • 1
    You say that "calls that line an error". At least include the error message in your question. – Keith Thompson Nov 09 '15 at 23:24
  • For unsigned situations you describe (or when signedness is unknown because the value's type is a template type parameter), I do "negation" by subtracting the value from zero, of the same type. Like `size_t result = size_t(0) - my_size_t_value;` – Christopher Oicles Nov 10 '15 at 00:00
  • @πάντα ῥεῖ It is not obvious, nor even correct, that I "need the next larger signed type". Please see the answer and standards quote in the question I linked. But thanks for editing my question to add a tag I probably should have added myself. – JSF Nov 10 '15 at 00:54
  • I've posted [a new answer](http://stackoverflow.com/a/33621222/827263) to the linked question, but the edge case I discuss should not be relevant for VS 2012. You *really* need to include the error message in your question. – Keith Thompson Nov 10 '15 at 01:17
  • @KeithThompson, Thanks, as you estimated, that edge case is not relevant to my situation. If `std::size_t` were either narrower than `int` or narrower than 32 bit, the architecture would be totally unsuited to the project in question. I assume posting such an edge case as a new answer implies the standard has not evolved in a way that invalidates the basics of the **old** answer. – JSF Nov 10 '15 at 01:26
  • @JSF: You've said that VS2012 "calls that line an error". For the third time, **what was the error message**? – Keith Thompson Nov 10 '15 at 01:27
  • I need to do quite a bit of work to get that error message, which so far was seen and dealt with (I think improperly) by a coworker, leaving me only the "corrected" code. I will report back once I have the error message, by which time I expect I will also have the #pragma to suppress it. – JSF Nov 10 '15 at 01:30
  • 1
    @JSF: Ok. Until then, your question is unanswerable. – Keith Thompson Nov 10 '15 at 01:31
  • @JSF: "*I assume posting such an edge case as a new answer implies the standard has not evolved in a way that invalidates the basics of the old answer.*" -- I'm not quite sure what that means. The edge case is not new; it existed as an edge case at least as far back as ANSI C89. The existing answers didn't cover that edge case, which is why I posted my answer. – Keith Thompson Nov 10 '15 at 02:10
  • @KeithThompson, I only meant to note that the original answer was old enough that one might wonder whether it was still valid, but by making a subtle refinement to the original answer, you are implying a level of expertise at which I would expect that if the old answer had been invalidated but a later standards change, you would have mentioned that. (You didn't, so I concluded it hadn't). – JSF Nov 10 '15 at 13:42
  • `-1*U` (or better `0-U`) is vastly preferred to any pragma fiddling. You need to add a comment explaining why you need it anyway. The code remains short, transparent and portable. – n. m. could be an AI Nov 10 '15 at 14:45
  • @n.m. If better explained or supported, that kind of opinion is very much part of what I hoped to get by asking. But I find the bald claim that those would be better totally unconvincing. My own opinion is they would be worse (less understandable if uncommented, harder to clearly comment, less obviously standards compliant and less obviously efficient). – JSF Nov 10 '15 at 15:28
  • @n.m.: And `-U` is better yet. The mystery is why the compiler would complain about it (and why a small example is so difficult). – Keith Thompson Nov 10 '15 at 15:29
  • @KeithThompson: I really thought I was clear about this. For any individual warning, there is something you could put somewhere in the solution hierarchy to make that warning into an error. I don't normally use this build system nor this compiler. So I would have a hard time finding what was done where. I have no clue why whoever (on a different team in a big company) did so, might leave many more serious warnings as warnings, but convert that flawed warning to an error. I can just infer that they did. – JSF Nov 10 '15 at 15:44
  • 1
    @KeithThompson Naturally, -U alone is better if it passes compilation. But it doesn't due to any number of reasons, so the next best thing is needed. Is it `-U` surrounded by pragmas? I say no. – n. m. could be an AI Nov 10 '15 at 15:52
  • @n.m. Two reasons I disagree: I would never put something as strange as `-1*U` or `0-U` into code without a comment explaining why. That comment would be longer and more disruptive to code readability than the `#pragma` plus its comment. There is also an implied opinion on the compilation environment that required the change. A `#pragma` expresses a lower opinion of the environment than the code change expresses, and I have a **very** low opinion of whatever was done (injected into the command line) to convert this bad warning into a worse error. – JSF Nov 11 '15 at 18:04
  • "longer and more disruptive to code readability" Well that's assuming you miraculously don't need to explain why the heck you apply unary minus to an unsigned number in the first place. "expresses a lower opinion" Not sure why opinions should be coded. I prefer comments. – n. m. could be an AI Nov 11 '15 at 20:15

1 Answers1

2

#pragma warning (disable : 4146) // VS2012 unary minus operator applied to unsigned type

I didn't try to dig up what ill advised option someone added somewhere in the solution hierarchy to convert that unsound warning into a nasty error. Locally in the source code, in the several places where an unsigned or a std::size_t is correctly negated, the #pragma is quite reasonable as a comment to make it clear to any human code reviewer or MS compiler that negating an unsigned really was intentional.

I tested, that #pragma really does convert it all the way down from error to silent.

As a matter of project style, the compiler version in the comment on a warning disable tells only which compiler/version triggered the decision to add the #pragma. It is not intended to give any hint at how broad or narrow (other compilers or versions) the issue might be.

If I were in control of all aspects of this, I might decide that the command line option turning this warning into an error is so ill advised that it would be better to fix the command line than the source code (and worth all the extra effort to find the place whatever stupid option was injected into the command line). But in fact, I have no influence over that command line. I can make the final decision on what to do in these source files to compensate for bad decisions regarding the command line. I can't influence whatever I might consider to be bad decisions regarding the command line.

JSF
  • 5,281
  • 1
  • 13
  • 20
  • @KeithThompson, that was the first page I clicked on after I finally got the error number. But that page is at best totally misleading. It has the right warning number and warning text, but the explanation and example seem to be for a different enough situation that they probably have a different warning number. In any case they are not from any typical example of 4146. – JSF Nov 10 '15 at 16:34
  • It looks like `-2147483648` is the rationale for the warning, but the compiler warns about any application of unary `-` to an unsigned value. I'd be surprised if there were a separate warning number for the more general case. (But then again, I was surprised that the warning exists in the first place.) – Keith Thompson Nov 11 '15 at 05:05