简体   繁体   中英

Is it ok to store an 8- or 16-bit value to a 16-bit aligned buffer in this code?

I would like to save some value (8 or 16 bits) pointed by 8-bit pointer to a 16-bit aligned buffer.

extern volatile INT16U NvM_Zone[128] __attribute((nodp, addr(NVRAM1_PAGE1_FIRST_ADDRESS)));

Std_ReturnType NvM_WriteBlock(NvM_BlockIdType BlockId, INT8U *NvM_SrcPtr) {
    Std_ReturnType Res = E_OK;
    NvM_ConfigType *nvm_config = &NvMConfig;
    NvM_StatusType nvm_status = nvm_config->nvm_module_status;
    if ((nvm_status == NVM_COMPLETED)) {
        nvm_status = NVM_IN_PROGRESS;
        nvm_config->nvm_data_info = &g_NvmDataList[0];
        INT8U i = nvm_config->nvm_data_info[BlockId].data_start_addr;
        INT8U size = nvm_config->nvm_data_info[BlockId].data_size_in_byte;
        if (size == 2) {
            INT16U *src = (INT16U*)NvM_SrcPtr;
            INT16U *dst = &NvM_Zone[i];
            *dst = *src;
        } else {
            INT8U *src  = NvM_SrcPtr;
            INT16U *dst = &NvM_Zone[i];
            *dst = (INT16U)(*src);
        }       
        NVRAM_SavePage(0);      // NVRAM_content : 0 ~ 63
        NVRAM_SavePage(1);      // NVRAM_content : 64 ~ 127     
        //NVRAM_SavePage(NVRAM2_PAGE1);
        nvm_config->nvm_flash_cntr_in_rt++;
        nvm_status = NVM_COMPLETED;
        Res = E_OK;
    } else {
        Res = E_NOT_OK;
    }
    nvm_config->nvm_module_status = nvm_status;
    return Res;
}
  1. 16-bit value - Is it ok to save 16-bit value which is casted when parameterized in 8-bit pointer (alignment violation)? The final destination is a 16-bit buffer, it will be casted back to 16-bit alignment. is it fine?

  2. 8-bit value - As far as I know it should be fine with the code below. But any suggestion in coding a better way?

EDIT 1.

the NvM_SrcPtr pointer parameter is passed something like this.

INT8U Byte = 0x00U;
INT16U Word = 0x0000U;
NvM_WriteBlock(SPECIAL_MODE_TYPE_VAL, &Byte);
NvM_WriteBlock(SPECIAL_MODE_TYPE_VAL, (INT8U*)&Word);
#include <stdio.h>
#include <stdlib.h>
int main(){

    int i;



    unsigned __int8 GX=7;
    printf("Value:%d\n",GX);
    printf("%d\n",&GX);
    for(i=0;i<8;i++){
        printf("Bin:%d\n",GX&0b1<<i);
    }
    /*Pass INT8U to INT16U */
    unsigned __int16 *DDC;
    DDC=(unsigned __int16*)&GX;

    printf("Value:%d\n",*DDC);
    printf("%d\n",DDC);
    /*Clearly Address is same but printf may be diff*/
    for(i=0;i<8;i++){
        printf("Bin:%d\n",(*DDC)&0b1<<i);
    }
    for(i=8;i<16;i++){
        printf("Bin2:%d\n",(*DDC)&0b1<<i);
    }
    /*First 8 bit same*/
    /*other 8 bit not sure because another 8bit give by address is not legal because not alloc*/
    /*you can trans 8bit to 16bit using address if you dont fix another 8bit*/

    /*if you want cover another value please make another 8bit stay original value*/
    /*like below*/
    unsigned __int16 NewValue=80;
    *DDC=(*DDC)&(0xff00|NewValue);


    /*By the way in multithreading case dont use this method because memory use will be too complex*/





    return 0;
}

General rule is that you can dereference pointer only with correct type. You can convert pointer to other types, but if you want to dereference it, you need to convert it back to original type.

These pointer conversions are implementation defined . This means that different pointers can have different presentations on some systems, and you should read the compiler manual on how these work on your system. On typical modern system pointers usually use same representation and pointer conversions just work.

However, yours may be special case. You see character type pointers are a special exception in C standard: they are guaranteed to have representation that is convertible to other pointer types, and they can be always dereferenced even if they were derived from other pointer types. So, if INT8U is unsigned char (which is very likely), your pointer conversions are fine.

8-bit with no conversions is fine:

INT8U Byte = 0x00U;
INT8U *NvM_SrcPtr = &Byte;         // ok - matching type
INT8U *src = NvM_SrcPtr;           // ok - matching type
*dst = (INT16U)(*src);             // ok - dereference with original type

16-bit with conversions is most likely fine:

INT16U Word = 0x0000U;
INT8U *NvM_SrcPtr = &Word;         // impl.def or special case
INT16U *src = (INT16U*)NvM_SrcPtr; // impl.def or special case
*dst = *src;                       // ok - dereference with original type

16-bit -> 8-bit is most likely fine:

INT16U Word = 0x0000U;
INT8U *NvM_SrcPtr = &Word;         // impl.def or special case
INT8U *src = NvM_SrcPtr;           // ok - matching type
*dst = (INT16U)(*src);             // ok if INT8U is unsigned char

8-bit -> 16-bit is not fine:

INT8U Byte = 0x00U;
INT8U *NvM_SrcPtr = &Byte;         // ok - matching type
INT16U *src = (INT16U*)NvM_SrcPtr; // impl.def 
*dst = *src;                       // invalid - derefence with invalid type

As for the pointer alignment, this is something that you need to take care of. If you convert pointer to other type, then misalign it, and convert it back, you may have undefined behaviour .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM