Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » unsigned char error

This thread is locked; no one can reply to it. rss feed Print
unsigned char error
Neil Walker
Member #210
April 2000
avatar

Hello,
I'm compiling some (old) C code in new visual studio 2010 and it's now generating an error:

a value of type "char *" cannot be assigned to an entity of type "unsigned char *"

As far as I know, this type of pointer assignment is permitted and it always used to work? I know I can cast it, but why the error now?

In fact it's giving me errors on malloc (void*) wanting me to explicitly cast everything - I know MSVC has never been ANSI C compliant but it used to work in 2008 fine.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Sindisil
Member #12,453
December 2010

Have you set "Compile as C" in project properties?

LennyLen
Member #5,313
December 2004
avatar

Sindisil said:

Have you set "Compile as C" in project properties?

If it was compiling it as C instead of C++, it wouldn't throw an error, just a warning.

Sindisil
Member #12,453
December 2010

Well, assigning an unsigned char * to a variable of type char * is invalid in both C and C++ anyway, as signed char, char, and unsigned char are all different types. Older versions of VC++ simply did a crappy job of telling you so.

As for the return from malloc needing to be cast - in C++ it does need to be cast, as C++ admits no implicit pointer type coercion. Since malloc returns a void *, and you're attempting to assign to some other type of pointer, you need to cast the return.

C automagicaly coerces void * to and from any other pointer type, so there is no need to cast the return from malloc. In fact, it is considered by many (including myself) to be poor style to cast the return from malloc, as it can hide implicit declaration of malloc (i.e. the failure to #include <stdlib.h>.

When you sent "compile as c", V++ is actually reasonably compliant with C90 ... just not C99.

Neil Walker
Member #210
April 2000
avatar

Sorry, forgot to mention I was compiling as C and it's an error not a warning.

Sindisil said:

assigning an unsigned char * to a variable of type char * is invalid in both C and C++ anyway

This is what I read from a C spec:
"Assignment and pointer differences are permitted between pointers to types that are interchangeable but not identical, for example, unsigned char * and char *."

Quote:

so there is no need to cast the return from malloc. In fact, it is considered by many (including myself) to be poor style to cast the return from malloc

I know, but that's what MSVC2010 is telling me and I'm explicitly compiling as C (not even relying on it using the file extension as that doesn't work any more).

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Arthur Kalliokoski
Second in Command
February 2005
avatar

I'd guess that it's for programmers who might not know the possible problems with signed vs. unsigned chars. That's why they have all those deprecated warnings using string functions warning about buffer overflows. The vast majority of their own programmers need this stuff.

They all watch too much MSNBC... they get ideas.

Sindisil
Member #12,453
December 2010

If it's the error vs. warning that's bugging you, I assume you already ensured that "treat warnings as errors" is set to "no" in project properties?

As for implicit conversion of pointers, I don't know what "C spec" you're referencing, but that certainly isn't standard C!

And on the malloc cast warning, Microsoft also has unilaterally "deprecated" parts of the C standard library. Worst case, you could disable that warning for projects compiled as C.

I try to avoid using VC++, and, when I can't avoid it (like today), I stick to C++. It is, quite frankly, a rather annoying compiler, especially when used from within the Visual Studio IDE. IMHO, of course.

Kitty Cat
Member #2,815
October 2002
avatar

Sindisil said:

As for implicit conversion of pointers, I don't know what "C spec" you're referencing, but that certainly isn't standard C!

C is known for its lack of type safety. C will gladly implicitly convert between any pointer types, though sane compilers will give out a warning for incompatible types. If MSVC is throwing out an error for that in C code, it's broken.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Sindisil
Member #12,453
December 2010

No, a conforming Standard C90 or C99 compiler will most certainly not implicitly coerce pointer types, other than to and from void *.

It will, however, let you explicitly coerce virtually any type object to any other, via casting. If you apply a cast, the compiler is supposed to assume you know what you're doing and go ahead.

LennyLen
Member #5,313
December 2004
avatar

Sindisil said:

No, a conforming Standard C90 or C99 compiler will most certainly not implicitly coerce pointer types, other than to and from void *.

Just one minute with a C compiler will prove that incorrect.

#include <stdio.h>

int main() {

    unsigned char *uc;
    char c = 'f';

    uc = &c;
    printf("%c  %c", c, *uc);

    return 0;
    
}

Prints: f f

Evert
Member #794
November 2000
avatar

Sindisil said:

No, a conforming Standard C90 or C99 compiler will most certainly not implicitly coerce pointer types, other than to and from void *.

A C compiler will let you do whatever without casting pointers. Any decent C compiler will, however, give you a warning for any implicit cast other than from and to `void *`.
Disallowing implicit casts is a C++ feature.

Sindisil
Member #12,453
December 2010

LennyLen said:

Just one minute with a C compiler will prove that incorrect.#include <stdio.h>

int main() {

unsigned char *uc;
char c = 'f';

uc = &c;
printf("%c %c", c, *uc);

return 0;

}

Prints: f f

What a given C compiler does or doesn't flag is beside the point - the standard specifies what is and is not valid. Pointer conversion is a pretty simple issue, but, none the less, I'll take the time to look up and quote chapter and verse. I only have the C89 standard and draft C1x standards handy; I'll use the former, since C89 is still the most commonly used standard right now (sadly).

Section 3.3.16.1 specifies the semantics of simple assignment. With respect to pointer assignment, it says:

ANSI X3.159-1989 said:
 * both operands are pointers to qualified or unqualified versions of
   compatible types, and the type pointed to by the left has all the
   qualifiers of the type pointed to by the right;

 * one operand is a pointer to an object or incomplete type and the
   other is a pointer to a qualified or unqualified version of void, and
   the type pointed to by the left has all the qualifiers of the type
   pointed to by the right; or

In section 3.5.4.1, which describes pointer declarators, it says:

ANSI X3.159-1989 said:
   For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types.

Section 3.1.2.6 defines compatible types. It says, in part:

ANSI X3.159-1989 said:
3.1.2.6 Compatible type and composite type

   Two types have compatible type if their types are the same.
Additional rules for determining whether two types are compatible are
described in $3.5.2 for type specifiers, in $3.5.3 for type
qualifiers, and in $3.5.4 for declarators.

Finally, section 3.5.2 describes type specifiers. It says:

ANSI X3.159-1989 said:
 Each list of type specifiers shall be one of the following sets; the
type specifiers may occur in any order, possibly intermixed with the
other declaration specifiers.

 * void 

 * char 

 * signed char 

 * unsigned char 

 * short , signed short , short int , or signed short int 

 * unsigned short , or unsigned short int 

 * int , signed , signed int , or no type specifiers 

 * unsigned , or unsigned int 

 * long , signed long , long int , or signed long int 

 * unsigned long , or unsigned long int 

 * float 

 * double 

 * long double 

 * struct-or-union specifier 

 * enum-specifier 

 * typedef-name

Semantics

   Specifiers for structures, unions, and enumerations are discussed
in $3.5.2.1 through $3.5.2.3.  Declarations of typedef names are
discussed in $3.5.6.  The characteristics of the other types are
discussed in $3.1.2.5.

   Each of the above comma-separated lists designates the same type,
except that for bit-field declarations, signed int (or signed ) may
differ from int (or no type specifiers).

You'll note that the three char types are each in their own list. In other words, they are different types, and thus incompatible wrt type coercions. Note that type coercion in assignment is not the same as type promotion in expressions.

Go to: