2015-12-03 2 views
-1

Je travaille sur une extraction d'échantillon de fichier wave et je suis coincé avec ma petite partie. J'ai des données de 24 bits extraites d'un échantillon, disons AB0293 (MSB étant 1). J'utilise une variable int 32 bits pour stocker cela. Je suis incapable de comprendre comment faire cela. Qu'arriverait-il au MSB de cet exemple au format 32 bits? Et qu'arriverait-il aux bits restants?comportement du numéro signé en C

Les déclarations sont:

int32_t in2[10],in1[10]; 
FILE *fp1,*fp2; 

fread(&in2[0],1,index1, fp1);//index1=3 
//value of in2[0] after this operation is 0xAB0293(-ve value of 24 bits) 

fread(&in1[0],1,index1, fp2); 
//value of in1[0] after this operation is 0xA00232(-ve value of 24 bits) 

in1[0]=in1[0]-in2[0];//this is a 32 bit data operation(because of which i am getting wrong answer) 
+0

quel compilateur et quelle architecture? Utilisez-vous 'uint'? –

+1

Qu'est-ce que c'est «AB0293»? Aussi, avez-vous du code? –

+0

Il est normal de garder 8 bits restants = 0. Et ne comprends pas quel est le problème? – i486

Répondre

1

Maintenant que je vois comment vous lisez votre dossier, un beaucoup plus propre façon de le faire est d'être 100% clair sur le boutisme de votre dossier et de choisir le droit fonction.

Pour big endian J'ai immédiatement la solution:

uintmax_t readarrayvalue(const char * data, uint8_t len) 
{ 
    uintmax_t value = 0; 
    while (len) { 
     value <<= 8; 
     value |= *(data++) & 0xFF; 
     len--; 
    } 
    return value; 
} 

que vous pouvez utiliser pour lire une valeur arbitraire à partir d'un tableau en mémoire.

Si les données du tableau sont à LE au lieu de BE, vous pouvez faire quelque chose comme

uintmax_t readarrayvalue_le(const char * data, uint8_t len) 
{ 
    uintmax_t value = 0; 
    uint8_t shift = 0; 
    while (len) { 
     value |= (((uintmax_t)(*(data++))) & 0xFF) << shift; 
     len--; 
     shift += 8; 
    } 
    return value; 
} 

Ce dernier est un non testé. Peut-être qu'il serait préférable de

  • shift avec factor remplacer, qui est multiplié par 256 sur toutes les étapes
  • faire value += (((uintmax_t)(*(data++))) & 0xFF) * factor;

afin d'éviter tout problème.

+0

note: cela suppose le complément de 2 (pour la valeur stockée et l'implémentation C) –

+0

@PaulHankin Merci, oublié là-dessus. Je pense que je vais raccourcir ma réponse à la 2ème partie. – glglgl

+0

'value | = (* (data ++) & 0xFF) << shift;' ne fonctionne pas pour 'len> sizeof (int)'. En outre, il invoque un comportement indéfini pour 'len == sizeof (int)' en raison d'un dépassement arithmétique potentiel. – chqrlie

2

signe l'extension d'une valeur 24 bits peut être fait directement de cette façon:

int32_t sign_extend_24_to_32(int32_t value) { 
    return value | -(value & 0x800000); 
} 

Cela ne suppose le complément de 2 pour l'échantillon et la CPU hôte et la disponibilité de type int32_t, mais cela ne devrait pas être un problème pour l'OP.

Vous avez lu 3 octets dans les éléments de tableau in1[0] et in2[0]. Vous devez initialiser le tableau à 0. Vous devez également comprendre dans quel ordre les octets sont stockés dans le fichier (little-endian ou big-endian) et dans quel ordre l'ordinateur hôte les utilise. Votre code actuel suppose little-endian pour les deux.

2

Ce qui suit suppose, puisque votre énoncé du problème est pas tout à fait clair:

  • Vous avez un fichier avec des séquences de 3 octets consécutifs (MSB first = big endian) représentant les valeurs 2-complément 24 bits.
  • Vous souhaitez lire ces valeurs dans une valeur de complément à 32 bits signée, où le bit le plus significatif des 24 bits est le bit de signe.
  • Vous souhaitez conserver le signe dans la valeur de 32 bits (c'est-à-dire que vous souhaitez étendre la valeur d'un complément à 2 à 24 bits à une valeur de complément à 32 bits).

Pour que cela soit indépendant de l'endianness de votre CPU, vous lisez les valeurs octet par octet.

#include <stdint.h> 
... 
uint8_t v[3]; /* Array to store a 24 bit value byte-by-byte. */ 
int32_t value; /* Converted 32-bit value in machine endianness. */ 

if (fread (v, 1, sizeof v, fp1) == sizeof v) { 
    /* Convert big-endian to machine endianness. */ 
    value = (v[0] << 16) + (v[1] << 8) + v[2]; 
    /* Sign extend when negative. */ 
    if (value & 0x00800000u) 
     /* Fancy, non-undefined way to compute value |= 0xFF000000. */ 
     value = -((value^0xFFFFFFu) + 1); 
} else { 
    /* fread found eof or error */ 
} 
+0

Votre code suppose 'INT_MAX> = 0xFFFFFF'. Une expression simple non-définie est 'value - = 0x1000000;' – chqrlie

+0

Merci @chqrlie, je savais que le calcul explicite à 2-complément permettrait une solution plus simple. Je vais le laisser à des fins éducatives :-) – Jens