tags:

views:

165

answers:

5
int utstrlen(char* src){
    int length=0 ;
    if(isOurs(src) ==1){
        length = src - 2 * sizeof(int);
    }
    return length;
}

I got the warning C4047: '=' : 'int' differs in levels of indirection from 'char *' error from line length = src - 2 * sizeof(int); can someone explain what's wrong with it? Thank you!

A: 

src is a char *; length is an int. The compiler is therefore treating this line as similar to:

length = (int) (src - 2 * sizeof(int));

I'm not sure what's confusing to you about the warning, and I'm also confused about what your code is trying to do. My suggestion, then, is to try the following test code, and see what it prints:

void test(void) {
    char *foo = "hello\n";

    printf("%s\n", foo);
    printf("%d\n", (int) foo);
    printf("%s\n", foo+1);
    printf("%d\n", ((int) foo) + 1);
}

you'll note that arithmetic makes more sense in one use of the pointer than in the other.

Aidan Cully
A: 

src - 2 * sizeof(int) is pointer arithmetic - the result of that expression is another char* pointer. You're trying to assign a char* to length, which is an int, and that's why you're getting the error. I don't know what this function is supposed to do, but if you really wanted to you could cast the value to an int: length = (int)(src - 2 * sizeof(int)). But again, I don't see the use in your function.

wj32
A: 

Sure.

src is a pointer; 2 * sizeof(int) is an integer value.

While it is indeed legal

  1. to subtract two pointers from one another (the result being the differences in their addresses, as an integer integral type, perhaps size_tptrdiff_t), and also

  2. to subtract an integer from a pointer (the result being a pointer to a location a bit before that pointer),

it is not legal to try to assign the result from (2) to an integer variable (length).

Carl Smotricz
The result of (1) is still a pointer-width type, not an int.
wj32
Right you are, it's an integral type but not type `int`. Depending on the compiler, though, it could be inter-assignable with int.
Carl Smotricz
It is of type `ptrdiff_t`, although strictly speaking, you can only subtract two pointers that point to members in an array.
Alok
My C is definitely rusty. Thanks, corrected.
Carl Smotricz
+1  A: 

I suspect you have a string struct like this:

struct string {
    int length;
    int somethingelse; /* thanks alok */
    char *str;
}

and this function is trying to access the length field when given a pointer to the str? Am I correct? I imagine this is what isOurs checks for (to make sure it's not any old string). In which case, you want this:

length = (*((int*)(src - 2))) * sizeof(int);

int utstrlen(char* src){
    int length=0 ;
    if(isOurs(src) ==1){
          length = *((int*)(src - (2 * sizeof(int)))); /* from str moveback 2 ints worth*/
    }
    else {
        //return strlen(src) ?
    }
    return length;
}

But ideally you wouldn'd do that. It's not portable or maintainable. What happens if the compiler inserts padding you don't know about? The C99 standard says it will not put padding between the 0 sized array and the previous field, but there's nothing to stop it going mad with the other ones (if you have a mixture of types, for instance).

What happens if someone comes along later and inserts more data into the structure? Naturally, they'd have to put it before the field str, as the 'struct hack' works by having it at the end. Ideally you should be using offsetof() to do this, which is a standard macro. Alok provides a better solution here and http://stackoverflow.com/questions/2038910/ugly-macro-interpretation-just-1-line/2039133#2039133

edit (it seems in the 2 minutes it took me to type that new last paragraph, Alok's offsetof() answer has been accepted over this one ;) )

Pod
That doesn't look right either. `length = *((int *)src - 2);` seems more likely.
caf
ah yes, I forgot to cast :)
Pod
I am not sure what you're trying to do in `length = ...` line. Most likely his struct has two `int` members before the `char *`, and subtracting `2*sizeof(int)` gives him an address to the beginning of the struct (assuming no padding). A better method is to use `offsetof` macro.
Alok
entirely. If he said "this is what I'm doing" I was going to just say "use offsetof() instead".I assumed he wanted to go back 2 bytes from str, which would point him at the start of length (if it was 2 bytes long.... :/).Your theory of 2 ints sounds more likely.
Pod
See http://stackoverflow.com/questions/2038910/ugly-macro-interpretation-just-1-line for his struct definition.
Alok
I see you've already answered him there with offsetof(). no need for my millions of brackets now :)
Pod
@Pod: since your answer was accepted, maybe you should add a line to the effect of "this is not portable, and one should use offsetof for doing such things." This will help others reading this question and the answer.
Alok
+3  A: 

Based upon your previous question, you want

length = *((int *)(src - 2 * sizeof(int)));

although that assumes no padding. A better way would be to use offsetof():

String *beg = (String *)(src - offsetof(struct String, ptr));
length = beg->length;

I am assuming you are using the struct from your previous question.

Alok