This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

void pointer behaviour ?

Hi,
I observed a strange behaviour (for me only) of void pointer. I wrote a code to access an integer through void pointer as below:

void *ptr;
int a[2] = {1,2};

ptr = (int *)&a;
ptr++; // This is giving error: Unknown Size

Why the above increment statement is giving error as i already cast the pointer to int type ?

Can anybody help me in understanding this ?

Karthik K.

  • andy, do u take classes for C?
    got to start from 'c'ing c..

  • is there a reason to learn C, and THEn apply to ucontrollers, certainly there should be other ways,

    There are as many 'ways' as there are peaches in Gaffney, but "to learn C, and THEn apply to ucontrollers" is the best and - surprise - fastest.

    Erik

  • "((int *)ptr)++;

    warning: #1441-D: nonstandard cast on lvalue

    Is that ok?"

    Although some compilers accept it, it's really an error because the postfix increment operator requires a modifiable lvalue and a cast does not yield an lvalue.

    What does work on all compilers is:

    ptr = ((int *)ptr) + 1;
    

  • So the above statement gets the address of an address.

    That interpretation would be consistent with the way you'd expect operator & to work, but that behavior doesn't actually match the C spec.

    Array names are not always the same as pointers to the first element. Most of the time, yes, but not always.

    When applied to an array, the & operator does nothing.

    char c[100];

    char* p = c;
    char* q = &c;

    assert (p == q); // this assertion is true

    (This makes some sense if you ask yourself what &c means. It's the address of the array c, which is the same as the address of its first element. Also, since c is really a constant determined no later than load time, it doesn't really have an address to take. It's not explicitly stored anywhere.)

    Similarly, sizeof behaves a little oddly around arrays.

    assert (sizeof(c) == 100 * sizeof(char));
    assert (sizeof(c) != sizeof(char*));

    But, this latter point is only true when sizeof can "see" the array definition. If c were a parameter to a function, then sizeof(c) would indeed be the size of a pointer, no matter what the array declaration was.

  • "Similarly, sizeof behaves a little oddly around arrays. "

    Why, is it bcoz its feels shy of the C compiler
    or it tends to run away out of "shyness",

  • Could somebody guide me what is to be done,
    any REAOSN, to get anm answer without being re-directed,
    Any Suggestions, Ideas are Most Welcome,
    Waiting for Your reply,

    Thanks a lot,

  • "Could somebody guide me what is to be done,"

    Have you utilized any of the information you've been given? Post the code in question, but in a slightly larger context (an entire function perhaps), so we can see what you are trying to do.

  • The type "void" has no size (not size 0, but no defined size at all). p is a pointer to void. The ++ operator increments a pointer by the size of the typed pointed to (not by 1, but by 1 * sizeof(*p)). For a pointer-to-void, there is no size, and thus you can't increment a pointer-to-void. Hence the compiler warning, "Unknown size".

    The cast in the assignment statement does not change the type of p. C is a compiled language with static typing. Types cannot be changed dynamically at run time. All a cast does is temporarily override the type of an expression during evaluation.

    A U8* is often a more useful type for "pointer to anything" than is a void* when you're trying to do pointer arithmetic. A U8 has a sizeof 1, which is what most people usually expect for "generic" pointer math. The ANSI void type can be assigned a value of any pointer type, but the type itself can be manipulated only in limited ways.

  • When applied to an array, the & operator does nothing.

    Incorrect. It does exactly what it always does: it takes the address of its operand. The difference is that the type of the result is different. &array give you a result of type "pointer to array", not "pointer to element". I.e.

    assert (p == q); // this assertion is true
    


    is a warranted assumption only in this particular case, because the base type of the array was 'char', for which special rules apply (because 'char' also serves as the "byte" of C). Strictly speaking,

    type array[100];
    type *ptr = &array;
    


    is illegal for all types other than character types, because the type of the initializer is different from the type of the object being defined. Lint will not let you get away with this.

  • Sorry a bit off subject. I find that the Realview compiler wobbles if I try to use U8. Is there a U16 and S8, S16?

    typedef unsigned char U8;
    typedef unsigned short U16;

    This works. But I seem to have seen U8 mentioned in the release notes somewhere as a new feature, or am I hallucinating. I had forgotten about it until I read this post.

  • "I find that the Realview compiler wobbles if I try to use U8."

    I don't understand what "wobbles" means in this context.

    "Is there a U16 and S8, S16?"

    I think you'll find that toolchains typically do not define the above-mentioned types and leave that for the user if they want. Forward looking toolchains (forward to C99, that is) might define something similar using the 'intn_t exact-width integer types.

  • My mistake, from the post I had the impression that U8 etc should be available without resorting to :-

    typedef unsigned char U8;

    But from what you say, I shouldn't expect them to be defined. Just had that funny feeling that I had read it in a Keil update somewhere.

    Thanks.

  • "U8" isn't an official C type. But every C programmer I know has adopted some similar local convention for naming types with explicit widths. Often you see UINT8. Some people like BYTE.

    C99 introduced new headers, inttypes.h and stdint.h, with official names for these types as well as new "half-open" types. So, you could use "uint8_t" to be modern and official.

    (I may be too stuck in my old rut to switch, and never liked the ANSI _t, for that matter. I already know it's a type from the syntax, thank you; that's why it's in typedef and comes right before the variable...)

    A "half-open" type is one where the compiler has some freedom to choose the representation, under some constraint. For example, there's uint_least16_t and uint_fast16_t. The former is any unsigned in the compiler likes so long as it has at least 16 bits. This type is useful for such things as loop counters, where you know you have to be able to count to a certain value, but otherwise don't care about the width. The _fastN types specify the fastest representation with at least N bits. These types leave the compiler some flexibility to optimize while still letting the programmer guaranteed needed sizes.

    For structures that represent hardware or message formats, you'll still want the absolute, fixed size types like int16_t.

    The C99 headers also have lots of useful macros and types for dealing with common problems: min and max integer values, making sure literals are a particular bit width, correct pointer arithmetic types and bounds, and so on.

    I'd like to see Keil introduce header files with support for these types on the way to C99 compliance.