2

Is there any way to convert a signed integer into an array of bytes in NXC? I can't use explicit type casting or pointers either, due to language limitations.

I've tried:

for(unsigned long i = 1; i <= 2; i++)
{
    MM_mem[id.idx] = ((val & (0xFF << ((2 - i) * 8)))) >> ((2 - i) * 8));

    id.idx++;
}

But it fails.

EDIT: This works... It just wasn't downloading. I've wasted about an hour trying to figure it out. >_>


EDIT: In NXC, >> is a arithmetic shift. int is a signed 16-bit integer type. A byte is the same thing as unsigned char.


NXC is 'Not eXactly C', a relative of C, but distinctly different from C.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135

3 Answers3

4

How about

    unsigned char b[4];

    b[0] = (x & 0xFF000000) >> 24;
    b[1] = (x & 0x00FF0000) >> 16;
    b[2] = (x & 0x0000FF00) >> 8;
    b[3] = x & 0xFF;
cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • You're assuming the target architecture has a 32-bit long type. – djs Apr 25 '11 at 06:04
  • @djs I am assuming nothing. He didn't specify it so I showed one possibility. From this he can surely adapt it to his word size / byte order. – cnicutar Apr 25 '11 at 06:05
  • @cnicutar For all we know his problem is that he thinks it is 32-bit. That said, I don't think we've established that he's asking about C yet, either. – djs Apr 25 '11 at 06:08
  • @djs I am sure the concepts of masking & shifting are general enough. – cnicutar Apr 25 '11 at 06:10
  • Oh wait... *someone* had unplugged the USB, so it wasn't downloading. It's working, and I'll accept this soon. – Mateen Ulhaq Apr 25 '11 at 06:52
2

Question originally tagged ; this answer may not be applicable to Not eXactly C.

What is the problem with this:

int value;
char bytes[sizeof(int)];

bytes[0] = (value >>  0) & 0xFF;
bytes[1] = (value >>  8) & 0xFF;
bytes[2] = (value >> 16) & 0xFF;
bytes[3] = (value >> 24) & 0xFF;

You can regard it as an unrolled loop. The shift by zero could be omitted; the optimizer would certainly do so. Even though the result of right-shifting a negative value is not defined, there is no problem because this code only accesses the bits where the behaviour is defined.

This code gives the bytes in a little-endian order - the least-significant byte is in bytes[0]. Clearly, big-endian order is achieved by:

int value;
char bytes[sizeof(int)];

bytes[3] = (value >>  0) & 0xFF;
bytes[2] = (value >>  8) & 0xFF;
bytes[1] = (value >> 16) & 0xFF;
bytes[0] = (value >> 24) & 0xFF;
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • To be completely pedantic (if we're talking about C), there are no "bits where the behavior is defined" (§6.5.7 in C1x, but the same text appears in C99): "If [the left operand] has a signed type and a negative value, *the resulting value is implementation-defined*." That said, the question seems to be about some other language altogether. – Stephen Canon Apr 25 '11 at 06:03
  • @Stephen: yes, though the underlying issue is usually whether an arithmetic or a logical shift is employed at the CPU (assembly) level, and the difference is whether the sign bit or a zero bit is propagated; but the result is that the high-order bits are all zeroes or all ones (and it is implementation defined - not undefined or unspecified - which it is). But, the code shown does not access the high-order bits. Nevertheless, you are technically correct - the standard does not say what will happen, but it does require the implementation to document what will happen. – Jonathan Leffler Apr 25 '11 at 06:07
  • absolutely; I'm merely pointing out that the implementation could document that right-shift of a negative value can produce a trap representation, or return bits from `/dev/random`, or do any number of other things, and still be within the standard. However, as the question doesn't actually seem to be about the C language, this is rather besides the point. – Stephen Canon Apr 25 '11 at 06:17
  • Nope, NXC uses [a bizarre form of :)] arithmetic shifts, and this doesn't work. – Mateen Ulhaq Apr 25 '11 at 06:58
  • @muntoo: the NXC manual doesn't indicate that there's anything bizarre about the shift operators - the only somewhat unusual feature is that the `int` type is 16 bits rather than 32 as assumed above, and that's only unusual in the world of desktop computing; in the world of embedded computing in hardware where NXC is used, I suspect 16-bit `int` is still fairly common. The NXC manual is not self-contained; it doesn't cover a lot of the finer details of the language behaviour. – Jonathan Leffler Apr 25 '11 at 14:15
2

The best way to do this in NXC with the opcodes available in the underlying VM is to use FlattenVar to convert any type into a string (aka byte array with a null added at the end). It results in a single VM opcode operation where any of the above options which use shifts and logical ANDs and array operations will require dozens of lines of assembly language.

task main()
{
  int x = Random(); // 16 bit random number - could be negative
  string data;
  data = FlattenVar(x); // convert type to byte array with trailing null
  NumOut(0, LCD_LINE1, x);
  for (int i=0; i < ArrayLen(data)-1; i++)
  {
#ifdef __ENHANCED_FIRMWARE
    TextOut(0, LCD_LINE2-8*i, FormatNum("0x%2.2x", data[i]));
#else
    NumOut(0, LCD_LINE2-8*i, data[i]);
#endif
  }
  Wait(SEC_4);
}

The best way to get help with LEGO MINDSTORMS and the NXT and Not eXactly C is via the mindboards forums at http://forums.mindboards.net/