0
votes

I have the following code (only key code) and minimal example code, but it is illegal because of the line OFFSET_PTR(pFileBothDirInfo->NextEntryOffset, pFileBothDirInfo); (IDE error: expression must be a modifiable value. Compile: error C2106: '=': left operand must be l-value.)

char packet_bytes[9] = {0};

int main(int argc, char* argv[]) {
    printf("(int)sizeof(smb2_query_directory_response_t) = %d\n", (int)sizeof(smb2_query_directory_response_t));
    printf("(int)sizeof(smb2_FileBothDirectoryInformation_t) = %d\n", (int)sizeof(smb2_FileBothDirectoryInformation_t));

    const smb2_query_directory_response_t*  pSMB2QueryDirectoryResponse = (smb2_query_directory_response_t*)packet_bytes;
    const smb2_FileBothDirectoryInformation_t *pFileBothDirInfo = pSMB2QueryDirectoryResponse->OutputBufferLength ? REINTERPRET_CAST(const smb2_FileBothDirectoryInformation_t*, pSMB2QueryDirectoryResponse->Buffer) : NULL;
    while (pFileBothDirInfo)
    {
        // ideone runs on linux with a compiler who consider wchar_t 4 bytes?
        // https://stackguides.com/questions/16944750/c-unicode-characters-printing
        //wprintf(L"%.*s|%.*s\n", pFileBothDirInfo->FileNameLength/2, pFileBothDirInfo->FileName, pFileBothDirInfo->ShortNameLength/2, pFileBothDirInfo->ShortName);
        if (pFileBothDirInfo->NextEntryOffset)
        {
            offset_ptr(pFileBothDirInfo->NextEntryOffset, pFileBothDirInfo);

            const unsigned char *ptrTemp;
            ptrTemp = ((const unsigned char*)pFileBothDirInfo + 10);
            //be equivalent to 
            //((const unsigned char*)pFileBothDirInfo) = ( (const unsigned char*)pFileBothDirInfo + 10 );
            OFFSET_PTR(pFileBothDirInfo->NextEntryOffset, pFileBothDirInfo);
            *((int *)10) = 100;
            printf("ptrTemp = %p", ptrTemp);
        } 
        else
        {
            break;
        }
    }
    return 0;
}

I also referred to L-Value and R-Value Expressions

An lvalue has an address that your program can access. Examples of lvalue expressions include variable names, including const variables, array elements, function calls that return an lvalue reference, bit-fields, unions, and class members.

and L-Value and R-Value Expressions, which points out that the following code is legal, but The VS2015 IDE and its compiler gave me an error.

char *p;
short i;
long l;

(long *)p = &l;     /* Legal cast   */
(long)i = l;        /* Illegal cast */

It has a similar error using ideone compiler:

Compilation error   #stdin compilation error #stdout 0s 15232KB
prog.cpp: In function ‘int main(int, char**)’:
prog.cpp:259:33: error: lvalue required as left operand of assignment
    OFFSET_PTR(pFileBothDirInfo->NextEntryOffset, pFileBothDirInfo);
                                 ^
prog.cpp:235:107: note: in definition of macro ‘OFFSET_PTR’
 #define OFFSET_PTR(byte_offset, ref_ptr) ((const unsigned char*)ref_ptr = (const unsigned char*)ref_ptr + byte_offset)

I think (const unsigned char*)pFileBothDirInfo has an address, but why it isn't considered as a lvalue?

References

2
Unrelated to your problem, but there's a specific printf format specifier for the type size_t (which is returned by sizeof): "%zu". Or just use std::cout and the overloaded << operator.Some programmer dude
I also can't help but think that your minimal reproducible example could be even more minimal, without losing any important information.Some programmer dude
*((int *)10) = 100; What the hell is this?Daniel Langr
That last piece of code relies on an MS "extension" that makes some "cast-assignments" legal. Neither assignment is valid in standard C or C++.molbdnilo
Quoting from the section 3.10 you linked to (item 6): "An expression which holds a temporary object resulting from a cast to a nonreference type is an rvalue".molbdnilo

2 Answers

2
votes

I think (const unsigned char*)pFileBothDirInfo has an address, but why it isn't considered as a lvalue?

You think wrong.

The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is [an lvalue reference type or an rvalue reference to function type] and an xvalue if T is [an rvalue reference to object type]; otherwise the result is a prvalue.

[expr.cast] ([] brackets added to group clauses)

const unsigned char* is not any kind of reference type, so the result is a prvalue.

You are creating a value of type const unsigned char*. Why would it be associated with the storage of an object of type const smb2_FileBothDirectoryInformation_t *?

MSVC allows (long *)p = &l; as an extension.

1
votes

OFFSET_PTR is broken.

Yes, pFileBothDirInfo has an address, but (const unsigned char*)pFileBothDirInfo is a temporary. An rvalue. That's what happens when you perform a cast to a value type! You get a fresh object of the new type.

The other problem is that it is const. You can't modify const things. That's what it means.