5

This isn't working in visual studio 2010 , it gives me the following error

void main (void)
{
     unsigned char* test = "ATGST"; 

}

Edit 1: My question is why this works on Embedded systems, but doesn't work on PC?

enter image description here

But when I change it to :

 char* test = "ATGST";  

it works.

The main thing that I write code for embedded systems using C, and I use visual studio to test some functions so I don't have to test it in real time on a Micro-controller.

I need an explanation, because Micro-controllers accepts the first code.

Kijewski
  • 25,517
  • 12
  • 101
  • 143
xsari3x
  • 442
  • 2
  • 12
  • 36
  • 2
    Why would you _expect_ that to work? `char` and `unsigned char` are two different types. – ildjarn Jun 29 '12 at 22:54
  • Probable duplicate: http://stackoverflow.com/questions/3834608/string-literal-to-basic-stringunsigned-char – Christopher Berman Jun 29 '12 at 22:55
  • Check VS options. You'll see if it must treat char as signed or as unsigned. – Adriano Repetti Jun 29 '12 at 22:55
  • One should ask himself how does `void main()` work?? – Eitan T Jun 29 '12 at 22:55
  • 2
    @ildjarn hmmmm actually **char** and **unsigned char** _may_ be the same type. You can force VS to treat the _generic_ **char** type as **signed char** or **unsigned char**. – Adriano Repetti Jun 29 '12 at 22:57
  • @ildjarn I always use unsigned char in embedded code written for micro controllers – xsari3x Jun 29 '12 at 22:58
  • 5
    @Adriano : The C++ standard disagrees: §3.9.1/1 "*Plain `char`, `signed char`, and `unsigned char` are three distinct types.*" @xsari3x : Then those compilers are not conforming. – ildjarn Jun 29 '12 at 23:00
  • @Adriano so it's related to VS options , not to C language synatx ? – xsari3x Jun 29 '12 at 23:00
  • Just out of curiosity: Why do you need to specifically use unsigned char? (Looks like your intention in the example is to store strings, not numbers) – Jite Jun 29 '12 at 23:02
  • @xsari3x for C syntax (but someone should check the standard) it's allowed. For C++ syntax it shouldn't be (as pointed by ildjarn in C++ it's even disallowed). For before C++ compilers it's a little bit implementation dependant. – Adriano Repetti Jun 29 '12 at 23:03
  • 2
    For hosted (non-embedded) systems, `void main (void)` is incorrect. =(Well, mostly; an implementation is permitted to allow it, but there's no good reason to write it that way. Use `int main(void)` instead. For freestanding (embedded) systems, use whatever the compiler supports -- which may well be `void main(void)`. – Keith Thompson Jun 29 '12 at 23:03
  • 1
    The C standard also says: "Irrespective of the choice made, char is a separate type from the other two and is not compatible with either." with respect to `char`, `signed char` and `unsigned char`. – Daniel Fischer Jun 29 '12 at 23:08
  • @DanielFischer but also "compilers have the latitude to define char to have the same range, representation, and behavior as either signed char or unsigned char." – Adriano Repetti Jun 29 '12 at 23:13
  • 1
    @Adriano It _must_ have the same range, representation and behaviour as either `signed char` or `unsigned char`, yet it must be a different type. – Daniel Fischer Jun 29 '12 at 23:21
  • @DanielFischer when a type have the same range, representation and behavior of another type then the conversion is implicit. "unsigned char: used internally for string comparison functions even though these functions operate on character data. Consequently, the result of a string comparison does not depend on whether plain char is signed..." – Adriano Repetti Jun 29 '12 at 23:26
  • 3
    @Adriano : Conversion from `char` to `unsigned char` must be implicit, but conversion from `char*` to `unsigned char*` must _not_, just as conversion from `int*` to `long*` must not even if `int` and `long` are the same size. – ildjarn Jun 29 '12 at 23:30
  • @ildjarn you're right!!! – Adriano Repetti Jun 30 '12 at 08:02
  • The solution of course is to use C, since in C it doesn't care that you're "making a mistake"... at the end of the day, char is at least a byte. That's all that matters. Strings are just arrays of bytes. Again, this is all that really matters. It's only "an error" because C++ compilers say it is. – Jimmio92 Jun 17 '21 at 04:12

5 Answers5

12

Edited to conform to the removal of the C++ tag and to appease the embedded tag.

First, the problem at hand, you are trying to pass a char[] literal into an unsigned char*. You can't really equate char with either unsigned or signed, it is a bit special in that regard. Also, a string literal is given unique storage and should never be modified. If you're dealing with characters, you need to use a standard char* in which char[] can decay into. You could forcefully cast it, but I don't like to recommend such things. It is safe to do, as one of the comments pointed out. Actually, it is actually one of the rare things that are really a safety no-brainer.

But there is far too little space for a tight answer to provide enough qualification on reinterpret_casting, which is basically saying to the compiler that you know what you're doing. That is potentially very dangerous and should only be done when you're quite sure about the problem at hand. The char is usually just generic, not even signed or unsigned. Since an unsigned char has a bigger range than a char and usually char uses the positive subset of the signed char to describe characters (or any other kind of data that can fit), if your data is not in the extended positive range, you're good to go. But, do conform to the environment and code safely.

On the entry point function - conforming edit

Since it has been established that you work on an embedded system, this implies that your program is very likely not required to return anything, so it can remain void main() (it could also be the case that it requires very different returns specified by the given embedded system, the OP knows the most about the requirements his system imposes). In a lot of cases, the reason you can remain with void is because there is no environment/OS to appease, nobody to communicate with. But embedded systems can also be quite specialized and it is best to approach by studying the given platform in detail in order to satisfy the requirements imposed (if any).

Community
  • 1
  • 1
  • If the language is C (as tagged) then string literals have type `char []` not `const char []`. MSVC seems nonconformant here. – R.. GitHub STOP HELPING ICE Jun 30 '12 at 00:07
  • @R.. : I think this answer was posted before the `c++` tag was edited out of the question. – ildjarn Jun 30 '12 at 00:08
  • @R.. I scour only through C++ questions, just noticed it was removed. But yes, C differentiates in that regard. I'll edit to compensate. –  Jun 30 '12 at 00:11
  • 2
    "I don't like to recommend such things" - Casting a pointer to `(unsigned char *)` is one of the few safe pointer casts you *can* do, you can always alias anything as `unsigned char`. Windows is always 2's complement, so you don't even have to worry about the theoretical possibility that `*((unsigned char*)ptr) != (unsigned char)(*ptr)`. Still, if it's going to point at a string literal then it should be `(const unsigned char*)` in C even though the language doesn't require it: so close to being recommendable and yet so far... – Steve Jessop Jun 30 '12 at 02:05
  • Your rant about main() is irrelevant and possibly incorrect. This is clearly tagged as embedded, and the OP is trying to run the code both on an embedded system and on Windows. On an embedded system, the code is perfectly fine, on Windows it wouldn't compile on a strictly-conforming C compiler (VC++ is not). Read [this](http://stackoverflow.com/questions/5296163/why-is-the-type-of-the-main-function-in-c-and-c-left-to-the-user-to-define/5296593#5296593) before commenting on the format of main() in the future. – Lundin Jul 02 '12 at 06:17
  • @Lundin It wasn't initially. We mentioned it 5000 times. And yes, you're right. It was written in general fashion. When you're working with embedded systems, there is a slight assert that you know what the given platform needs/offers. –  Jul 02 '12 at 06:53
  • @Lundin I further edited the answer to be more conforming, removing unnecessary details pertaining to OS/host-dependent applications. –  Jul 02 '12 at 07:02
5

For one, you need a const in there. And secondly, char != unsigned char, and also (uniquely) != signed char.

String literals are of type const char[N]- for an appropriate size N, and therefore can only be converted to a const char*. Note that the language has a special rule allowing you to implicitly drop the const but it's still UB to modify a string literal, making it a terribly bad idea to do so.

The micro-controller's C implementation is non-conforming in this regard. It would be better to simply use const char*, as is correct, rather than try to hack VS into accepting incorrect code.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 1
    @xsari3x: There's actually not much more to it than I said. If you want to know more, you'll have to read the C Standard. – Puppy Jun 29 '12 at 23:09
  • 2
    The question is tagged C, and in C string literals have type `char[N]`, not `const char[N]`. – Daniel Fischer Jun 29 '12 at 23:10
  • @DanielFischer: I'm pretty sure that's just as deprecated in C as it is in C++. In either case, it's just as bad to drop the `const`. – Puppy Jun 29 '12 at 23:11
  • @DanielFischer That's just an oversight because the C standard brought us the fine stuff called UB. Not a practice to indulge in. What does it mean to change a literal, something that is given unique storage. const-ness is a matter of sanity, not language. –  Jun 29 '12 at 23:11
  • @DeadMG In C, there is no `const` to drop here. Sure, assigning string literals to `const char*` gives you more safety, so it's recommended, but the standard says the type of string literals is `char[N]` and attempting to modify one is UB. – Daniel Fischer Jun 29 '12 at 23:14
  • @xsari3x Undefined Behaviour. – Daniel Fischer Jun 29 '12 at 23:16
  • @DomagojPandža I doubt it's an oversight. In the beginning, there was no `const`. – Daniel Fischer Jun 29 '12 at 23:18
3

I believe this is the case of assigning string to unsigned char *.

Well, when you assign a string value, it will assign ASCII values associated with characters, so you should use char * in place of unsigned char *.

if you want to assign values other than strings, characters then your implementation is correct.

hope it helps.

Kinjal Patel
  • 405
  • 2
  • 7
0

If you are using character types for text, use the unqualified char.

If you are using character types as numbers, use unsigned char. unsigned char, which gives you at least the 0 to 255 range.

for more information: What is an unsigned char?

Community
  • 1
  • 1
John Riselvato
  • 12,854
  • 5
  • 62
  • 89
0

My question is why this works on Embedded systems, but doesn't work on PC?

Most likely because you are accidentally compiling the PC code in C++ which has stricter type checking than C. In C, it doesn't matter the slightest whether you use unsigned char or plain char, the code will compile just fine.

However, there are some issues with your code that should be fixed, as suggested in other answers. If the code needs to run on embedded and Windows both, you should rewrite it as:

#ifdef _WIN32
int main (void)
#else
void main (void)
#endif
{
  const unsigned char* test = "ATGST"; 

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