How can I force the size of an int for debugging purposes?What happens when I use the wrong format specifier?Which integral promotions do take place when printing a char?How do I determine the size of my array in C?Strange program hang, what does this mean in debug?How can I get a file's size in C?Dumping the values of the registers in GCCHow can I get the list of files in a directory using C or C++?How to generate a random int in C?Clean x86_64 assembly output with gcc?How to debug win 32 process to find memory access violation?Jumping to the next “instruction” using gdbWhat is the correct use of multiple input and output operands in extended GCC asm?

What does the expression "A Mann!" means

Are there any examples of a variable being normally distributed that is *not* due to the Central Limit Theorem?

Examples of smooth manifolds admitting inbetween one and a continuum of complex structures

How badly should I try to prevent a user from XSSing themselves?

What reasons are there for a Capitalist to oppose a 100% inheritance tax?

Why is consensus so controversial in Britain?

Why is it a bad idea to hire a hitman to eliminate most corrupt politicians?

Avoiding the "not like other girls" trope?

How can I deal with my CEO asking me to hire someone with a higher salary than me, a co-founder?

How to tell a function to use the default argument values?

How to prevent "they're falling in love" trope

Can I run a new neutral wire to repair a broken circuit?

What about the virus in 12 Monkeys?

Intersection Puzzle

Is there a hemisphere-neutral way of specifying a season?

Why can't we play rap on piano?

Should I tell management that I intend to leave due to bad software development practices?

How dangerous is XSS?

Can my sorcerer use a spellbook only to collect spells and scribe scrolls, not cast?

What's the in-universe reasoning behind sorcerers needing material components?

Can the Meissner effect explain very large floating structures?

Should I cover my bicycle overnight while bikepacking?

Which is the best way to check return result?

Mathematica command that allows it to read my intentions



How can I force the size of an int for debugging purposes?


What happens when I use the wrong format specifier?Which integral promotions do take place when printing a char?How do I determine the size of my array in C?Strange program hang, what does this mean in debug?How can I get a file's size in C?Dumping the values of the registers in GCCHow can I get the list of files in a directory using C or C++?How to generate a random int in C?Clean x86_64 assembly output with gcc?How to debug win 32 process to find memory access violation?Jumping to the next “instruction” using gdbWhat is the correct use of multiple input and output operands in extended GCC asm?













20















I have two builds for a piece of software I'm developing, one for an embedded system where the size of an int is 16 bits, and another for testing on the desktop where the size of an int is 32 bits. I am using fixed width integer types from <stdint.h>, but integer promotion rules still depend on the size of an int.



Ideally I would like something like the following code to print 65281 (integer promotion to 16 bits) instead of 4294967041 (integer promotion to 32 bits) because of integer promotion, so that it exactly matches the behavior on the embedded system. I want to be sure that code which gives one answer during testing on my desktop gives the exact same answer on the embedded system. A solution for either GCC or Clang would be fine.



#include <stdio.h>
#include <stdint.h>

int main(void)
uint8_t a = 0;
uint8_t b = -1;

printf("%un", a - b);

return 0;



EDIT:



The example I gave might not have been the best example, but I really do want integer promotion to be to 16 bits instead of 32 bits. Take the following example:



#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
uint16_t d = (a - b) / (a - c);

printf("%" PRIu16 "n", d);

return 0;



The output is 0 on a 32-bit system because of truncation from integer division after promotion to a (signed) int, as opposed to 32767.



The best answer so far seem to be to use an emulator, which is not what I was hoping for, but I guess does make sense. It does seem like it should be theoretically possible for a compiler to generate code that behaves as if the size of an int were 16 bits, but I guess it maybe shouldn't be too surprising that there's no easy way in practice to do this, and there's probably not much demand for such a mode and any necessary runtime support.



EDIT 2:



This is what I've explored so far: there is in fact a version of GCC which targets the i386 in 16-bit mode at https://github.com/tkchia/gcc-ia16. The output is a DOS COM file, which can be run in DOSBox. For instance, the two files:



test.c



#include <stdint.h>

uint16_t result;

void test16(void)
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
result = (a - b) / (a - c);



main.c



#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

extern uint16_t result;
void test16(void);

int main(void)
test16();
printf("result: %" PRIu16"n", result);

return 0;



can be compiled with



$ ia16-elf-gcc -Wall test16.c main.c -o a.com


to produce a.com which can be run in DOSBox.



D:>a
result: 32767


Looking into things a little further, ia16-elf-gcc does in fact produce a 32-bit elf as an intermediate, although the final link output by default is a COM file:



$ ia16-elf-gcc -Wall -c test16.c -o test16.o
$ file test16.o
test16.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped


I can force it to link with main.c compiled with regular GCC, but not surprisingly, the resulting executable segfaults.



$ gcc -m32 -c main.c -o main.o
$ gcc -m32 -Wl,-m,elf_i386,-s,-o,outfile test16.o main.o
$ ./outfile
Segmentation fault (core dumped)


From a post here, it seems like it should theoretically be possible to link the 16-bit code output from ia16-elf-gcc to 32-bit code, although I'm not actually sure how. Then there is also the issue of actually running 16-bit code on a 64-bit OS. More ideal would be a compiler that still uses regular 32-bit/64-bit registers and instructions for performing the arithmetic, but emulates the arithmetic through library calls similar to how for instance a uint64_t is emulated on a (non-64-bit) microcontroller.



The closest I could find for actually running 16-bit code on x86-64 is here, and that seems experimental/completely unmaintained. At this point, just using an emulator is starting to seem like the best solution, but I will wait a little longer and see if anyone else has any ideas.



EDIT 3



I'm going to go ahead and accept antti's answer, although it's not the answer I was hoping to hear. If anyone is interested in what the output of ia16-elf-gcc is (I'd never even heard of ia16-elf-gcc before), here is the disassembly:



$ objdump -M intel -mi386 -Maddr16,data16 -S test16.o > test16.s


Notice that you must specify that it is 16 bit code, otherwise objdump interprets it as 32-bit code, which maps to different instructions (see further down).



test16.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push bp ; save frame pointer
1: 89 e5 mov bp,sp ; copy SP to frame pointer
3: 83 ec 08 sub sp,0x8 ; allocate 4 * 2bytes on stack
6: c7 46 fe 00 00 mov WORD PTR [bp-0x2],0x0 ; uint16_t a = 0
b: c7 46 fc 01 00 mov WORD PTR [bp-0x4],0x1 ; uint16_t b = 1
10: 8b 46 fe mov ax,WORD PTR [bp-0x2] ; ax = a
13: 83 c0 fe add ax,0xfffe ; ax -= 2
16: 89 46 fa mov WORD PTR [bp-0x6],ax ; uint16_t c = ax = a - 2
19: 8b 56 fe mov dx,WORD PTR [bp-0x2] ; dx = a
1c: 8b 46 fc mov ax,WORD PTR [bp-0x4] ; ax = b
1f: 29 c2 sub dx,ax ; dx -= b
21: 89 56 f8 mov WORD PTR [bp-0x8],dx ; temp = dx = a - b
24: 8b 56 fe mov dx,WORD PTR [bp-0x2] ; dx = a
27: 8b 46 fa mov ax,WORD PTR [bp-0x6] ; ax = c
2a: 29 c2 sub dx,ax ; dx -= c (= a - c)
2c: 89 d1 mov cx,dx ; cx = dx = a - c
2e: 8b 46 f8 mov ax,WORD PTR [bp-0x8] ; ax = temp = a - b
31: 31 d2 xor dx,dx ; clear dx
33: f7 f1 div cx ; dx:ax /= cx (unsigned divide)
35: 89 c0 mov ax,ax ; (?) ax = ax
37: 89 c0 mov ax,ax ; (?) ax = ax
39: a3 00 00 mov ds:0x0,ax ; ds[0] = ax
3c: 90 nop
3d: 89 c0 mov ax,ax ; (?) ax = ax
3f: 89 ec mov sp,bp ; restore saved SP
41: 5d pop bp ; pop saved frame pointer
42: 16 push ss ; ss
43: 1f pop ds ; ds =
44: c3 ret


Debugging the program in GDB, this instruction causes the segfault



movl $0x46c70000,-0x2(%esi)


Which is the first two move instructions for setting the value of a and b interpreted with the instruction decoded in 32-bit mode. The relevant disassembly (not specifying 16-bit mode) is as follows:



$ objdump -M intel -S test16.o > test16.s && cat test16.s

test16.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 ec 08 sub esp,0x8
6: c7 46 fe 00 00 c7 46 mov DWORD PTR [esi-0x2],0x46c70000
d: fc cld


The next step would be trying to figure out a way to put the processor into 16-bit mode. It doesn't even have to be real mode (google searches mostly turn up results for x86 16-bit real mode), it can even be 16-bit protected mode. But at this point, using an emulator definitely seems like the best option, and this is more for my curiosity. This is all also specific to x86. For reference here's the same file compiled in 32-bit mode, which has an implicit promotion to a 32-bit signed int (from running gcc -m32 -c test16.c -o test16_32.o && objdump -M intel -S test16_32.o > test16_32.s):



test16_32.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push ebp ; save frame pointer
1: 89 e5 mov ebp,esp ; copy SP to frame pointer
3: 83 ec 10 sub esp,0x10 ; allocate 4 * 4bytes on stack
6: 66 c7 45 fa 00 00 mov WORD PTR [ebp-0x6],0x0 ; uint16_t a = 0
c: 66 c7 45 fc 01 00 mov WORD PTR [ebp-0x4],0x1 ; uint16_t b = 0
12: 0f b7 45 fa movzx eax,WORD PTR [ebp-0x6] ; eax = a
16: 83 e8 02 sub eax,0x2 ; eax -= 2
19: 66 89 45 fe mov WORD PTR [ebp-0x2],ax ; uint16_t c = (uint16_t) (a-2)
1d: 0f b7 55 fa movzx edx,WORD PTR [ebp-0x6] ; edx = a
21: 0f b7 45 fc movzx eax,WORD PTR [ebp-0x4] ; eax = b
25: 29 c2 sub edx,eax ; edx -= b
27: 89 d0 mov eax,edx ; eax = edx (= a - b)
29: 0f b7 4d fa movzx ecx,WORD PTR [ebp-0x6] ; ecx = a
2d: 0f b7 55 fe movzx edx,WORD PTR [ebp-0x2] ; edx = c
31: 29 d1 sub ecx,edx ; ecx -= edx (= a - c)
33: 99 cdq ; EDX:EAX = EAX sign extended (= a - b)
34: f7 f9 idiv ecx ; EDX:EAX /= ecx
36: 66 a3 00 00 00 00 mov ds:0x0,ax ; ds = (uint16_t) ax
3c: 90 nop
3d: c9 leave ; esp = ebp (restore stack pointer), pop ebp
3e: c3 ret









share|improve this question



















  • 1





    You can't, because the underlying ABI expects from your program a specified alignment. To do that, you would have to recompile your whole system. that it exactly matches the behavior on the embedded system so don't use int if you want to be portable. The type of a-b expression is int - cast it to uint8_t and use PRNu8 to print it. If you are using long and int types, your program will never be portable. The line should have been printf("% "PRNu8 "n", (uint8_t)(a - b)); - that way it will print 1 on any architecture any system.

    – Kamil Cuk
    2 days ago







  • 2





    why you don`t use cast to uint16? printf("%un", (uint16_t)(a - b));

    – Paweł Dymowski
    2 days ago











  • you might try c++ version on the desktop. With a class Int16 you could overload the arithmetic operators.

    – Thomas G.
    2 days ago






  • 2





    A cast to uint16_t is only good for only so much...

    – Antti Haapala
    2 days ago






  • 1





    @PawełDymowski no, it's still UB to print signed int with %u. Because there were platforms where unsigned values may have trap bits. Which integral promotions do take place when printing a char?, What happens when I use the wrong format specifier?

    – phuclv
    yesterday















20















I have two builds for a piece of software I'm developing, one for an embedded system where the size of an int is 16 bits, and another for testing on the desktop where the size of an int is 32 bits. I am using fixed width integer types from <stdint.h>, but integer promotion rules still depend on the size of an int.



Ideally I would like something like the following code to print 65281 (integer promotion to 16 bits) instead of 4294967041 (integer promotion to 32 bits) because of integer promotion, so that it exactly matches the behavior on the embedded system. I want to be sure that code which gives one answer during testing on my desktop gives the exact same answer on the embedded system. A solution for either GCC or Clang would be fine.



#include <stdio.h>
#include <stdint.h>

int main(void)
uint8_t a = 0;
uint8_t b = -1;

printf("%un", a - b);

return 0;



EDIT:



The example I gave might not have been the best example, but I really do want integer promotion to be to 16 bits instead of 32 bits. Take the following example:



#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
uint16_t d = (a - b) / (a - c);

printf("%" PRIu16 "n", d);

return 0;



The output is 0 on a 32-bit system because of truncation from integer division after promotion to a (signed) int, as opposed to 32767.



The best answer so far seem to be to use an emulator, which is not what I was hoping for, but I guess does make sense. It does seem like it should be theoretically possible for a compiler to generate code that behaves as if the size of an int were 16 bits, but I guess it maybe shouldn't be too surprising that there's no easy way in practice to do this, and there's probably not much demand for such a mode and any necessary runtime support.



EDIT 2:



This is what I've explored so far: there is in fact a version of GCC which targets the i386 in 16-bit mode at https://github.com/tkchia/gcc-ia16. The output is a DOS COM file, which can be run in DOSBox. For instance, the two files:



test.c



#include <stdint.h>

uint16_t result;

void test16(void)
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
result = (a - b) / (a - c);



main.c



#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

extern uint16_t result;
void test16(void);

int main(void)
test16();
printf("result: %" PRIu16"n", result);

return 0;



can be compiled with



$ ia16-elf-gcc -Wall test16.c main.c -o a.com


to produce a.com which can be run in DOSBox.



D:>a
result: 32767


Looking into things a little further, ia16-elf-gcc does in fact produce a 32-bit elf as an intermediate, although the final link output by default is a COM file:



$ ia16-elf-gcc -Wall -c test16.c -o test16.o
$ file test16.o
test16.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped


I can force it to link with main.c compiled with regular GCC, but not surprisingly, the resulting executable segfaults.



$ gcc -m32 -c main.c -o main.o
$ gcc -m32 -Wl,-m,elf_i386,-s,-o,outfile test16.o main.o
$ ./outfile
Segmentation fault (core dumped)


From a post here, it seems like it should theoretically be possible to link the 16-bit code output from ia16-elf-gcc to 32-bit code, although I'm not actually sure how. Then there is also the issue of actually running 16-bit code on a 64-bit OS. More ideal would be a compiler that still uses regular 32-bit/64-bit registers and instructions for performing the arithmetic, but emulates the arithmetic through library calls similar to how for instance a uint64_t is emulated on a (non-64-bit) microcontroller.



The closest I could find for actually running 16-bit code on x86-64 is here, and that seems experimental/completely unmaintained. At this point, just using an emulator is starting to seem like the best solution, but I will wait a little longer and see if anyone else has any ideas.



EDIT 3



I'm going to go ahead and accept antti's answer, although it's not the answer I was hoping to hear. If anyone is interested in what the output of ia16-elf-gcc is (I'd never even heard of ia16-elf-gcc before), here is the disassembly:



$ objdump -M intel -mi386 -Maddr16,data16 -S test16.o > test16.s


Notice that you must specify that it is 16 bit code, otherwise objdump interprets it as 32-bit code, which maps to different instructions (see further down).



test16.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push bp ; save frame pointer
1: 89 e5 mov bp,sp ; copy SP to frame pointer
3: 83 ec 08 sub sp,0x8 ; allocate 4 * 2bytes on stack
6: c7 46 fe 00 00 mov WORD PTR [bp-0x2],0x0 ; uint16_t a = 0
b: c7 46 fc 01 00 mov WORD PTR [bp-0x4],0x1 ; uint16_t b = 1
10: 8b 46 fe mov ax,WORD PTR [bp-0x2] ; ax = a
13: 83 c0 fe add ax,0xfffe ; ax -= 2
16: 89 46 fa mov WORD PTR [bp-0x6],ax ; uint16_t c = ax = a - 2
19: 8b 56 fe mov dx,WORD PTR [bp-0x2] ; dx = a
1c: 8b 46 fc mov ax,WORD PTR [bp-0x4] ; ax = b
1f: 29 c2 sub dx,ax ; dx -= b
21: 89 56 f8 mov WORD PTR [bp-0x8],dx ; temp = dx = a - b
24: 8b 56 fe mov dx,WORD PTR [bp-0x2] ; dx = a
27: 8b 46 fa mov ax,WORD PTR [bp-0x6] ; ax = c
2a: 29 c2 sub dx,ax ; dx -= c (= a - c)
2c: 89 d1 mov cx,dx ; cx = dx = a - c
2e: 8b 46 f8 mov ax,WORD PTR [bp-0x8] ; ax = temp = a - b
31: 31 d2 xor dx,dx ; clear dx
33: f7 f1 div cx ; dx:ax /= cx (unsigned divide)
35: 89 c0 mov ax,ax ; (?) ax = ax
37: 89 c0 mov ax,ax ; (?) ax = ax
39: a3 00 00 mov ds:0x0,ax ; ds[0] = ax
3c: 90 nop
3d: 89 c0 mov ax,ax ; (?) ax = ax
3f: 89 ec mov sp,bp ; restore saved SP
41: 5d pop bp ; pop saved frame pointer
42: 16 push ss ; ss
43: 1f pop ds ; ds =
44: c3 ret


Debugging the program in GDB, this instruction causes the segfault



movl $0x46c70000,-0x2(%esi)


Which is the first two move instructions for setting the value of a and b interpreted with the instruction decoded in 32-bit mode. The relevant disassembly (not specifying 16-bit mode) is as follows:



$ objdump -M intel -S test16.o > test16.s && cat test16.s

test16.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 ec 08 sub esp,0x8
6: c7 46 fe 00 00 c7 46 mov DWORD PTR [esi-0x2],0x46c70000
d: fc cld


The next step would be trying to figure out a way to put the processor into 16-bit mode. It doesn't even have to be real mode (google searches mostly turn up results for x86 16-bit real mode), it can even be 16-bit protected mode. But at this point, using an emulator definitely seems like the best option, and this is more for my curiosity. This is all also specific to x86. For reference here's the same file compiled in 32-bit mode, which has an implicit promotion to a 32-bit signed int (from running gcc -m32 -c test16.c -o test16_32.o && objdump -M intel -S test16_32.o > test16_32.s):



test16_32.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push ebp ; save frame pointer
1: 89 e5 mov ebp,esp ; copy SP to frame pointer
3: 83 ec 10 sub esp,0x10 ; allocate 4 * 4bytes on stack
6: 66 c7 45 fa 00 00 mov WORD PTR [ebp-0x6],0x0 ; uint16_t a = 0
c: 66 c7 45 fc 01 00 mov WORD PTR [ebp-0x4],0x1 ; uint16_t b = 0
12: 0f b7 45 fa movzx eax,WORD PTR [ebp-0x6] ; eax = a
16: 83 e8 02 sub eax,0x2 ; eax -= 2
19: 66 89 45 fe mov WORD PTR [ebp-0x2],ax ; uint16_t c = (uint16_t) (a-2)
1d: 0f b7 55 fa movzx edx,WORD PTR [ebp-0x6] ; edx = a
21: 0f b7 45 fc movzx eax,WORD PTR [ebp-0x4] ; eax = b
25: 29 c2 sub edx,eax ; edx -= b
27: 89 d0 mov eax,edx ; eax = edx (= a - b)
29: 0f b7 4d fa movzx ecx,WORD PTR [ebp-0x6] ; ecx = a
2d: 0f b7 55 fe movzx edx,WORD PTR [ebp-0x2] ; edx = c
31: 29 d1 sub ecx,edx ; ecx -= edx (= a - c)
33: 99 cdq ; EDX:EAX = EAX sign extended (= a - b)
34: f7 f9 idiv ecx ; EDX:EAX /= ecx
36: 66 a3 00 00 00 00 mov ds:0x0,ax ; ds = (uint16_t) ax
3c: 90 nop
3d: c9 leave ; esp = ebp (restore stack pointer), pop ebp
3e: c3 ret









share|improve this question



















  • 1





    You can't, because the underlying ABI expects from your program a specified alignment. To do that, you would have to recompile your whole system. that it exactly matches the behavior on the embedded system so don't use int if you want to be portable. The type of a-b expression is int - cast it to uint8_t and use PRNu8 to print it. If you are using long and int types, your program will never be portable. The line should have been printf("% "PRNu8 "n", (uint8_t)(a - b)); - that way it will print 1 on any architecture any system.

    – Kamil Cuk
    2 days ago







  • 2





    why you don`t use cast to uint16? printf("%un", (uint16_t)(a - b));

    – Paweł Dymowski
    2 days ago











  • you might try c++ version on the desktop. With a class Int16 you could overload the arithmetic operators.

    – Thomas G.
    2 days ago






  • 2





    A cast to uint16_t is only good for only so much...

    – Antti Haapala
    2 days ago






  • 1





    @PawełDymowski no, it's still UB to print signed int with %u. Because there were platforms where unsigned values may have trap bits. Which integral promotions do take place when printing a char?, What happens when I use the wrong format specifier?

    – phuclv
    yesterday













20












20








20


1






I have two builds for a piece of software I'm developing, one for an embedded system where the size of an int is 16 bits, and another for testing on the desktop where the size of an int is 32 bits. I am using fixed width integer types from <stdint.h>, but integer promotion rules still depend on the size of an int.



Ideally I would like something like the following code to print 65281 (integer promotion to 16 bits) instead of 4294967041 (integer promotion to 32 bits) because of integer promotion, so that it exactly matches the behavior on the embedded system. I want to be sure that code which gives one answer during testing on my desktop gives the exact same answer on the embedded system. A solution for either GCC or Clang would be fine.



#include <stdio.h>
#include <stdint.h>

int main(void)
uint8_t a = 0;
uint8_t b = -1;

printf("%un", a - b);

return 0;



EDIT:



The example I gave might not have been the best example, but I really do want integer promotion to be to 16 bits instead of 32 bits. Take the following example:



#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
uint16_t d = (a - b) / (a - c);

printf("%" PRIu16 "n", d);

return 0;



The output is 0 on a 32-bit system because of truncation from integer division after promotion to a (signed) int, as opposed to 32767.



The best answer so far seem to be to use an emulator, which is not what I was hoping for, but I guess does make sense. It does seem like it should be theoretically possible for a compiler to generate code that behaves as if the size of an int were 16 bits, but I guess it maybe shouldn't be too surprising that there's no easy way in practice to do this, and there's probably not much demand for such a mode and any necessary runtime support.



EDIT 2:



This is what I've explored so far: there is in fact a version of GCC which targets the i386 in 16-bit mode at https://github.com/tkchia/gcc-ia16. The output is a DOS COM file, which can be run in DOSBox. For instance, the two files:



test.c



#include <stdint.h>

uint16_t result;

void test16(void)
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
result = (a - b) / (a - c);



main.c



#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

extern uint16_t result;
void test16(void);

int main(void)
test16();
printf("result: %" PRIu16"n", result);

return 0;



can be compiled with



$ ia16-elf-gcc -Wall test16.c main.c -o a.com


to produce a.com which can be run in DOSBox.



D:>a
result: 32767


Looking into things a little further, ia16-elf-gcc does in fact produce a 32-bit elf as an intermediate, although the final link output by default is a COM file:



$ ia16-elf-gcc -Wall -c test16.c -o test16.o
$ file test16.o
test16.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped


I can force it to link with main.c compiled with regular GCC, but not surprisingly, the resulting executable segfaults.



$ gcc -m32 -c main.c -o main.o
$ gcc -m32 -Wl,-m,elf_i386,-s,-o,outfile test16.o main.o
$ ./outfile
Segmentation fault (core dumped)


From a post here, it seems like it should theoretically be possible to link the 16-bit code output from ia16-elf-gcc to 32-bit code, although I'm not actually sure how. Then there is also the issue of actually running 16-bit code on a 64-bit OS. More ideal would be a compiler that still uses regular 32-bit/64-bit registers and instructions for performing the arithmetic, but emulates the arithmetic through library calls similar to how for instance a uint64_t is emulated on a (non-64-bit) microcontroller.



The closest I could find for actually running 16-bit code on x86-64 is here, and that seems experimental/completely unmaintained. At this point, just using an emulator is starting to seem like the best solution, but I will wait a little longer and see if anyone else has any ideas.



EDIT 3



I'm going to go ahead and accept antti's answer, although it's not the answer I was hoping to hear. If anyone is interested in what the output of ia16-elf-gcc is (I'd never even heard of ia16-elf-gcc before), here is the disassembly:



$ objdump -M intel -mi386 -Maddr16,data16 -S test16.o > test16.s


Notice that you must specify that it is 16 bit code, otherwise objdump interprets it as 32-bit code, which maps to different instructions (see further down).



test16.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push bp ; save frame pointer
1: 89 e5 mov bp,sp ; copy SP to frame pointer
3: 83 ec 08 sub sp,0x8 ; allocate 4 * 2bytes on stack
6: c7 46 fe 00 00 mov WORD PTR [bp-0x2],0x0 ; uint16_t a = 0
b: c7 46 fc 01 00 mov WORD PTR [bp-0x4],0x1 ; uint16_t b = 1
10: 8b 46 fe mov ax,WORD PTR [bp-0x2] ; ax = a
13: 83 c0 fe add ax,0xfffe ; ax -= 2
16: 89 46 fa mov WORD PTR [bp-0x6],ax ; uint16_t c = ax = a - 2
19: 8b 56 fe mov dx,WORD PTR [bp-0x2] ; dx = a
1c: 8b 46 fc mov ax,WORD PTR [bp-0x4] ; ax = b
1f: 29 c2 sub dx,ax ; dx -= b
21: 89 56 f8 mov WORD PTR [bp-0x8],dx ; temp = dx = a - b
24: 8b 56 fe mov dx,WORD PTR [bp-0x2] ; dx = a
27: 8b 46 fa mov ax,WORD PTR [bp-0x6] ; ax = c
2a: 29 c2 sub dx,ax ; dx -= c (= a - c)
2c: 89 d1 mov cx,dx ; cx = dx = a - c
2e: 8b 46 f8 mov ax,WORD PTR [bp-0x8] ; ax = temp = a - b
31: 31 d2 xor dx,dx ; clear dx
33: f7 f1 div cx ; dx:ax /= cx (unsigned divide)
35: 89 c0 mov ax,ax ; (?) ax = ax
37: 89 c0 mov ax,ax ; (?) ax = ax
39: a3 00 00 mov ds:0x0,ax ; ds[0] = ax
3c: 90 nop
3d: 89 c0 mov ax,ax ; (?) ax = ax
3f: 89 ec mov sp,bp ; restore saved SP
41: 5d pop bp ; pop saved frame pointer
42: 16 push ss ; ss
43: 1f pop ds ; ds =
44: c3 ret


Debugging the program in GDB, this instruction causes the segfault



movl $0x46c70000,-0x2(%esi)


Which is the first two move instructions for setting the value of a and b interpreted with the instruction decoded in 32-bit mode. The relevant disassembly (not specifying 16-bit mode) is as follows:



$ objdump -M intel -S test16.o > test16.s && cat test16.s

test16.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 ec 08 sub esp,0x8
6: c7 46 fe 00 00 c7 46 mov DWORD PTR [esi-0x2],0x46c70000
d: fc cld


The next step would be trying to figure out a way to put the processor into 16-bit mode. It doesn't even have to be real mode (google searches mostly turn up results for x86 16-bit real mode), it can even be 16-bit protected mode. But at this point, using an emulator definitely seems like the best option, and this is more for my curiosity. This is all also specific to x86. For reference here's the same file compiled in 32-bit mode, which has an implicit promotion to a 32-bit signed int (from running gcc -m32 -c test16.c -o test16_32.o && objdump -M intel -S test16_32.o > test16_32.s):



test16_32.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push ebp ; save frame pointer
1: 89 e5 mov ebp,esp ; copy SP to frame pointer
3: 83 ec 10 sub esp,0x10 ; allocate 4 * 4bytes on stack
6: 66 c7 45 fa 00 00 mov WORD PTR [ebp-0x6],0x0 ; uint16_t a = 0
c: 66 c7 45 fc 01 00 mov WORD PTR [ebp-0x4],0x1 ; uint16_t b = 0
12: 0f b7 45 fa movzx eax,WORD PTR [ebp-0x6] ; eax = a
16: 83 e8 02 sub eax,0x2 ; eax -= 2
19: 66 89 45 fe mov WORD PTR [ebp-0x2],ax ; uint16_t c = (uint16_t) (a-2)
1d: 0f b7 55 fa movzx edx,WORD PTR [ebp-0x6] ; edx = a
21: 0f b7 45 fc movzx eax,WORD PTR [ebp-0x4] ; eax = b
25: 29 c2 sub edx,eax ; edx -= b
27: 89 d0 mov eax,edx ; eax = edx (= a - b)
29: 0f b7 4d fa movzx ecx,WORD PTR [ebp-0x6] ; ecx = a
2d: 0f b7 55 fe movzx edx,WORD PTR [ebp-0x2] ; edx = c
31: 29 d1 sub ecx,edx ; ecx -= edx (= a - c)
33: 99 cdq ; EDX:EAX = EAX sign extended (= a - b)
34: f7 f9 idiv ecx ; EDX:EAX /= ecx
36: 66 a3 00 00 00 00 mov ds:0x0,ax ; ds = (uint16_t) ax
3c: 90 nop
3d: c9 leave ; esp = ebp (restore stack pointer), pop ebp
3e: c3 ret









share|improve this question
















I have two builds for a piece of software I'm developing, one for an embedded system where the size of an int is 16 bits, and another for testing on the desktop where the size of an int is 32 bits. I am using fixed width integer types from <stdint.h>, but integer promotion rules still depend on the size of an int.



Ideally I would like something like the following code to print 65281 (integer promotion to 16 bits) instead of 4294967041 (integer promotion to 32 bits) because of integer promotion, so that it exactly matches the behavior on the embedded system. I want to be sure that code which gives one answer during testing on my desktop gives the exact same answer on the embedded system. A solution for either GCC or Clang would be fine.



#include <stdio.h>
#include <stdint.h>

int main(void)
uint8_t a = 0;
uint8_t b = -1;

printf("%un", a - b);

return 0;



EDIT:



The example I gave might not have been the best example, but I really do want integer promotion to be to 16 bits instead of 32 bits. Take the following example:



#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
uint16_t d = (a - b) / (a - c);

printf("%" PRIu16 "n", d);

return 0;



The output is 0 on a 32-bit system because of truncation from integer division after promotion to a (signed) int, as opposed to 32767.



The best answer so far seem to be to use an emulator, which is not what I was hoping for, but I guess does make sense. It does seem like it should be theoretically possible for a compiler to generate code that behaves as if the size of an int were 16 bits, but I guess it maybe shouldn't be too surprising that there's no easy way in practice to do this, and there's probably not much demand for such a mode and any necessary runtime support.



EDIT 2:



This is what I've explored so far: there is in fact a version of GCC which targets the i386 in 16-bit mode at https://github.com/tkchia/gcc-ia16. The output is a DOS COM file, which can be run in DOSBox. For instance, the two files:



test.c



#include <stdint.h>

uint16_t result;

void test16(void)
uint16_t a = 0;
uint16_t b = 1;
uint16_t c = a - 2; // "-2": 65534
result = (a - b) / (a - c);



main.c



#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

extern uint16_t result;
void test16(void);

int main(void)
test16();
printf("result: %" PRIu16"n", result);

return 0;



can be compiled with



$ ia16-elf-gcc -Wall test16.c main.c -o a.com


to produce a.com which can be run in DOSBox.



D:>a
result: 32767


Looking into things a little further, ia16-elf-gcc does in fact produce a 32-bit elf as an intermediate, although the final link output by default is a COM file:



$ ia16-elf-gcc -Wall -c test16.c -o test16.o
$ file test16.o
test16.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped


I can force it to link with main.c compiled with regular GCC, but not surprisingly, the resulting executable segfaults.



$ gcc -m32 -c main.c -o main.o
$ gcc -m32 -Wl,-m,elf_i386,-s,-o,outfile test16.o main.o
$ ./outfile
Segmentation fault (core dumped)


From a post here, it seems like it should theoretically be possible to link the 16-bit code output from ia16-elf-gcc to 32-bit code, although I'm not actually sure how. Then there is also the issue of actually running 16-bit code on a 64-bit OS. More ideal would be a compiler that still uses regular 32-bit/64-bit registers and instructions for performing the arithmetic, but emulates the arithmetic through library calls similar to how for instance a uint64_t is emulated on a (non-64-bit) microcontroller.



The closest I could find for actually running 16-bit code on x86-64 is here, and that seems experimental/completely unmaintained. At this point, just using an emulator is starting to seem like the best solution, but I will wait a little longer and see if anyone else has any ideas.



EDIT 3



I'm going to go ahead and accept antti's answer, although it's not the answer I was hoping to hear. If anyone is interested in what the output of ia16-elf-gcc is (I'd never even heard of ia16-elf-gcc before), here is the disassembly:



$ objdump -M intel -mi386 -Maddr16,data16 -S test16.o > test16.s


Notice that you must specify that it is 16 bit code, otherwise objdump interprets it as 32-bit code, which maps to different instructions (see further down).



test16.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push bp ; save frame pointer
1: 89 e5 mov bp,sp ; copy SP to frame pointer
3: 83 ec 08 sub sp,0x8 ; allocate 4 * 2bytes on stack
6: c7 46 fe 00 00 mov WORD PTR [bp-0x2],0x0 ; uint16_t a = 0
b: c7 46 fc 01 00 mov WORD PTR [bp-0x4],0x1 ; uint16_t b = 1
10: 8b 46 fe mov ax,WORD PTR [bp-0x2] ; ax = a
13: 83 c0 fe add ax,0xfffe ; ax -= 2
16: 89 46 fa mov WORD PTR [bp-0x6],ax ; uint16_t c = ax = a - 2
19: 8b 56 fe mov dx,WORD PTR [bp-0x2] ; dx = a
1c: 8b 46 fc mov ax,WORD PTR [bp-0x4] ; ax = b
1f: 29 c2 sub dx,ax ; dx -= b
21: 89 56 f8 mov WORD PTR [bp-0x8],dx ; temp = dx = a - b
24: 8b 56 fe mov dx,WORD PTR [bp-0x2] ; dx = a
27: 8b 46 fa mov ax,WORD PTR [bp-0x6] ; ax = c
2a: 29 c2 sub dx,ax ; dx -= c (= a - c)
2c: 89 d1 mov cx,dx ; cx = dx = a - c
2e: 8b 46 f8 mov ax,WORD PTR [bp-0x8] ; ax = temp = a - b
31: 31 d2 xor dx,dx ; clear dx
33: f7 f1 div cx ; dx:ax /= cx (unsigned divide)
35: 89 c0 mov ax,ax ; (?) ax = ax
37: 89 c0 mov ax,ax ; (?) ax = ax
39: a3 00 00 mov ds:0x0,ax ; ds[0] = ax
3c: 90 nop
3d: 89 c0 mov ax,ax ; (?) ax = ax
3f: 89 ec mov sp,bp ; restore saved SP
41: 5d pop bp ; pop saved frame pointer
42: 16 push ss ; ss
43: 1f pop ds ; ds =
44: c3 ret


Debugging the program in GDB, this instruction causes the segfault



movl $0x46c70000,-0x2(%esi)


Which is the first two move instructions for setting the value of a and b interpreted with the instruction decoded in 32-bit mode. The relevant disassembly (not specifying 16-bit mode) is as follows:



$ objdump -M intel -S test16.o > test16.s && cat test16.s

test16.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 ec 08 sub esp,0x8
6: c7 46 fe 00 00 c7 46 mov DWORD PTR [esi-0x2],0x46c70000
d: fc cld


The next step would be trying to figure out a way to put the processor into 16-bit mode. It doesn't even have to be real mode (google searches mostly turn up results for x86 16-bit real mode), it can even be 16-bit protected mode. But at this point, using an emulator definitely seems like the best option, and this is more for my curiosity. This is all also specific to x86. For reference here's the same file compiled in 32-bit mode, which has an implicit promotion to a 32-bit signed int (from running gcc -m32 -c test16.c -o test16_32.o && objdump -M intel -S test16_32.o > test16_32.s):



test16_32.o: file format elf32-i386


Disassembly of section .text:

00000000 <test16>:
0: 55 push ebp ; save frame pointer
1: 89 e5 mov ebp,esp ; copy SP to frame pointer
3: 83 ec 10 sub esp,0x10 ; allocate 4 * 4bytes on stack
6: 66 c7 45 fa 00 00 mov WORD PTR [ebp-0x6],0x0 ; uint16_t a = 0
c: 66 c7 45 fc 01 00 mov WORD PTR [ebp-0x4],0x1 ; uint16_t b = 0
12: 0f b7 45 fa movzx eax,WORD PTR [ebp-0x6] ; eax = a
16: 83 e8 02 sub eax,0x2 ; eax -= 2
19: 66 89 45 fe mov WORD PTR [ebp-0x2],ax ; uint16_t c = (uint16_t) (a-2)
1d: 0f b7 55 fa movzx edx,WORD PTR [ebp-0x6] ; edx = a
21: 0f b7 45 fc movzx eax,WORD PTR [ebp-0x4] ; eax = b
25: 29 c2 sub edx,eax ; edx -= b
27: 89 d0 mov eax,edx ; eax = edx (= a - b)
29: 0f b7 4d fa movzx ecx,WORD PTR [ebp-0x6] ; ecx = a
2d: 0f b7 55 fe movzx edx,WORD PTR [ebp-0x2] ; edx = c
31: 29 d1 sub ecx,edx ; ecx -= edx (= a - c)
33: 99 cdq ; EDX:EAX = EAX sign extended (= a - b)
34: f7 f9 idiv ecx ; EDX:EAX /= ecx
36: 66 a3 00 00 00 00 mov ds:0x0,ax ; ds = (uint16_t) ax
3c: 90 nop
3d: c9 leave ; esp = ebp (restore stack pointer), pop ebp
3e: c3 ret






c gcc clang integer-promotion






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 22 hours ago







JDW

















asked 2 days ago









JDWJDW

1909




1909







  • 1





    You can't, because the underlying ABI expects from your program a specified alignment. To do that, you would have to recompile your whole system. that it exactly matches the behavior on the embedded system so don't use int if you want to be portable. The type of a-b expression is int - cast it to uint8_t and use PRNu8 to print it. If you are using long and int types, your program will never be portable. The line should have been printf("% "PRNu8 "n", (uint8_t)(a - b)); - that way it will print 1 on any architecture any system.

    – Kamil Cuk
    2 days ago







  • 2





    why you don`t use cast to uint16? printf("%un", (uint16_t)(a - b));

    – Paweł Dymowski
    2 days ago











  • you might try c++ version on the desktop. With a class Int16 you could overload the arithmetic operators.

    – Thomas G.
    2 days ago






  • 2





    A cast to uint16_t is only good for only so much...

    – Antti Haapala
    2 days ago






  • 1





    @PawełDymowski no, it's still UB to print signed int with %u. Because there were platforms where unsigned values may have trap bits. Which integral promotions do take place when printing a char?, What happens when I use the wrong format specifier?

    – phuclv
    yesterday












  • 1





    You can't, because the underlying ABI expects from your program a specified alignment. To do that, you would have to recompile your whole system. that it exactly matches the behavior on the embedded system so don't use int if you want to be portable. The type of a-b expression is int - cast it to uint8_t and use PRNu8 to print it. If you are using long and int types, your program will never be portable. The line should have been printf("% "PRNu8 "n", (uint8_t)(a - b)); - that way it will print 1 on any architecture any system.

    – Kamil Cuk
    2 days ago







  • 2





    why you don`t use cast to uint16? printf("%un", (uint16_t)(a - b));

    – Paweł Dymowski
    2 days ago











  • you might try c++ version on the desktop. With a class Int16 you could overload the arithmetic operators.

    – Thomas G.
    2 days ago






  • 2





    A cast to uint16_t is only good for only so much...

    – Antti Haapala
    2 days ago






  • 1





    @PawełDymowski no, it's still UB to print signed int with %u. Because there were platforms where unsigned values may have trap bits. Which integral promotions do take place when printing a char?, What happens when I use the wrong format specifier?

    – phuclv
    yesterday







1




1





You can't, because the underlying ABI expects from your program a specified alignment. To do that, you would have to recompile your whole system. that it exactly matches the behavior on the embedded system so don't use int if you want to be portable. The type of a-b expression is int - cast it to uint8_t and use PRNu8 to print it. If you are using long and int types, your program will never be portable. The line should have been printf("% "PRNu8 "n", (uint8_t)(a - b)); - that way it will print 1 on any architecture any system.

– Kamil Cuk
2 days ago






You can't, because the underlying ABI expects from your program a specified alignment. To do that, you would have to recompile your whole system. that it exactly matches the behavior on the embedded system so don't use int if you want to be portable. The type of a-b expression is int - cast it to uint8_t and use PRNu8 to print it. If you are using long and int types, your program will never be portable. The line should have been printf("% "PRNu8 "n", (uint8_t)(a - b)); - that way it will print 1 on any architecture any system.

– Kamil Cuk
2 days ago





2




2





why you don`t use cast to uint16? printf("%un", (uint16_t)(a - b));

– Paweł Dymowski
2 days ago





why you don`t use cast to uint16? printf("%un", (uint16_t)(a - b));

– Paweł Dymowski
2 days ago













you might try c++ version on the desktop. With a class Int16 you could overload the arithmetic operators.

– Thomas G.
2 days ago





you might try c++ version on the desktop. With a class Int16 you could overload the arithmetic operators.

– Thomas G.
2 days ago




2




2





A cast to uint16_t is only good for only so much...

– Antti Haapala
2 days ago





A cast to uint16_t is only good for only so much...

– Antti Haapala
2 days ago




1




1





@PawełDymowski no, it's still UB to print signed int with %u. Because there were platforms where unsigned values may have trap bits. Which integral promotions do take place when printing a char?, What happens when I use the wrong format specifier?

– phuclv
yesterday





@PawełDymowski no, it's still UB to print signed int with %u. Because there were platforms where unsigned values may have trap bits. Which integral promotions do take place when printing a char?, What happens when I use the wrong format specifier?

– phuclv
yesterday












3 Answers
3






active

oldest

votes


















18














You can't, unless you find some very special compiler. It would break absolutely everything, including your printf call. The code generation in the 32-bit compiler might not even be able to produce the 16-bit arithmetic code as it is not commonly needed.



Have you considered using an emulator instead?






share|improve this answer
































    6














    You need an entire runtime environment including all the necessary libraries to share the ABI you're implementing.



    If you want to run your 16-bit code on a 32-bit system, your most likely chance of success is to run it in a chroot that has a comparable runtime environment, possibly using qemu-user-static if you need ISA translation too. That said, I'm not sure that any of the platforms supported by QEMU has a 16-bit ABI.



    It might be possible to write yourself a set of 16-bit shim libraries, backed by your platform's native libraries - but I suspect the effort would outweigh the benefit to you.



    Note that for the specific case of running 32-bit x86 binaries on a 64-bit amd64 host, Linux kernels are often configured with dual-ABI support (you still need the appropriate 32-bit libraries, of course).






    share|improve this answer






























      2














      You could make the code itself be more aware about the data sizes it is handling, by for example doing:



      printf("%hun", a - b);


      From fprintf's docs:




      h



      Specifies that a following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int or unsigned short int before printing);







      share|improve this answer




















      • 1





        but that's besides the problem actually, and %hu wouldn't be correct (though essentially the same representation) if the uint16_t on the target is typedef'd to int.

        – Antti Haapala
        2 days ago







      • 1





        @AnttiHaapala: Why exactly wouldn't it be correct for an int?

        – alk
        2 days ago












      • hmm... how about just using PRI16u :D

        – Antti Haapala
        2 days ago











      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55450866%2fhow-can-i-force-the-size-of-an-int-for-debugging-purposes%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      18














      You can't, unless you find some very special compiler. It would break absolutely everything, including your printf call. The code generation in the 32-bit compiler might not even be able to produce the 16-bit arithmetic code as it is not commonly needed.



      Have you considered using an emulator instead?






      share|improve this answer





























        18














        You can't, unless you find some very special compiler. It would break absolutely everything, including your printf call. The code generation in the 32-bit compiler might not even be able to produce the 16-bit arithmetic code as it is not commonly needed.



        Have you considered using an emulator instead?






        share|improve this answer



























          18












          18








          18







          You can't, unless you find some very special compiler. It would break absolutely everything, including your printf call. The code generation in the 32-bit compiler might not even be able to produce the 16-bit arithmetic code as it is not commonly needed.



          Have you considered using an emulator instead?






          share|improve this answer















          You can't, unless you find some very special compiler. It would break absolutely everything, including your printf call. The code generation in the 32-bit compiler might not even be able to produce the 16-bit arithmetic code as it is not commonly needed.



          Have you considered using an emulator instead?







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 2 days ago

























          answered 2 days ago









          Antti HaapalaAntti Haapala

          85.8k16163205




          85.8k16163205























              6














              You need an entire runtime environment including all the necessary libraries to share the ABI you're implementing.



              If you want to run your 16-bit code on a 32-bit system, your most likely chance of success is to run it in a chroot that has a comparable runtime environment, possibly using qemu-user-static if you need ISA translation too. That said, I'm not sure that any of the platforms supported by QEMU has a 16-bit ABI.



              It might be possible to write yourself a set of 16-bit shim libraries, backed by your platform's native libraries - but I suspect the effort would outweigh the benefit to you.



              Note that for the specific case of running 32-bit x86 binaries on a 64-bit amd64 host, Linux kernels are often configured with dual-ABI support (you still need the appropriate 32-bit libraries, of course).






              share|improve this answer



























                6














                You need an entire runtime environment including all the necessary libraries to share the ABI you're implementing.



                If you want to run your 16-bit code on a 32-bit system, your most likely chance of success is to run it in a chroot that has a comparable runtime environment, possibly using qemu-user-static if you need ISA translation too. That said, I'm not sure that any of the platforms supported by QEMU has a 16-bit ABI.



                It might be possible to write yourself a set of 16-bit shim libraries, backed by your platform's native libraries - but I suspect the effort would outweigh the benefit to you.



                Note that for the specific case of running 32-bit x86 binaries on a 64-bit amd64 host, Linux kernels are often configured with dual-ABI support (you still need the appropriate 32-bit libraries, of course).






                share|improve this answer

























                  6












                  6








                  6







                  You need an entire runtime environment including all the necessary libraries to share the ABI you're implementing.



                  If you want to run your 16-bit code on a 32-bit system, your most likely chance of success is to run it in a chroot that has a comparable runtime environment, possibly using qemu-user-static if you need ISA translation too. That said, I'm not sure that any of the platforms supported by QEMU has a 16-bit ABI.



                  It might be possible to write yourself a set of 16-bit shim libraries, backed by your platform's native libraries - but I suspect the effort would outweigh the benefit to you.



                  Note that for the specific case of running 32-bit x86 binaries on a 64-bit amd64 host, Linux kernels are often configured with dual-ABI support (you still need the appropriate 32-bit libraries, of course).






                  share|improve this answer













                  You need an entire runtime environment including all the necessary libraries to share the ABI you're implementing.



                  If you want to run your 16-bit code on a 32-bit system, your most likely chance of success is to run it in a chroot that has a comparable runtime environment, possibly using qemu-user-static if you need ISA translation too. That said, I'm not sure that any of the platforms supported by QEMU has a 16-bit ABI.



                  It might be possible to write yourself a set of 16-bit shim libraries, backed by your platform's native libraries - but I suspect the effort would outweigh the benefit to you.



                  Note that for the specific case of running 32-bit x86 binaries on a 64-bit amd64 host, Linux kernels are often configured with dual-ABI support (you still need the appropriate 32-bit libraries, of course).







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 2 days ago









                  Toby SpeightToby Speight

                  17.4k134368




                  17.4k134368





















                      2














                      You could make the code itself be more aware about the data sizes it is handling, by for example doing:



                      printf("%hun", a - b);


                      From fprintf's docs:




                      h



                      Specifies that a following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int or unsigned short int before printing);







                      share|improve this answer




















                      • 1





                        but that's besides the problem actually, and %hu wouldn't be correct (though essentially the same representation) if the uint16_t on the target is typedef'd to int.

                        – Antti Haapala
                        2 days ago







                      • 1





                        @AnttiHaapala: Why exactly wouldn't it be correct for an int?

                        – alk
                        2 days ago












                      • hmm... how about just using PRI16u :D

                        – Antti Haapala
                        2 days ago















                      2














                      You could make the code itself be more aware about the data sizes it is handling, by for example doing:



                      printf("%hun", a - b);


                      From fprintf's docs:




                      h



                      Specifies that a following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int or unsigned short int before printing);







                      share|improve this answer




















                      • 1





                        but that's besides the problem actually, and %hu wouldn't be correct (though essentially the same representation) if the uint16_t on the target is typedef'd to int.

                        – Antti Haapala
                        2 days ago







                      • 1





                        @AnttiHaapala: Why exactly wouldn't it be correct for an int?

                        – alk
                        2 days ago












                      • hmm... how about just using PRI16u :D

                        – Antti Haapala
                        2 days ago













                      2












                      2








                      2







                      You could make the code itself be more aware about the data sizes it is handling, by for example doing:



                      printf("%hun", a - b);


                      From fprintf's docs:




                      h



                      Specifies that a following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int or unsigned short int before printing);







                      share|improve this answer















                      You could make the code itself be more aware about the data sizes it is handling, by for example doing:



                      printf("%hun", a - b);


                      From fprintf's docs:




                      h



                      Specifies that a following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int or unsigned short int before printing);








                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited 2 days ago

























                      answered 2 days ago









                      alkalk

                      59.2k765179




                      59.2k765179







                      • 1





                        but that's besides the problem actually, and %hu wouldn't be correct (though essentially the same representation) if the uint16_t on the target is typedef'd to int.

                        – Antti Haapala
                        2 days ago







                      • 1





                        @AnttiHaapala: Why exactly wouldn't it be correct for an int?

                        – alk
                        2 days ago












                      • hmm... how about just using PRI16u :D

                        – Antti Haapala
                        2 days ago












                      • 1





                        but that's besides the problem actually, and %hu wouldn't be correct (though essentially the same representation) if the uint16_t on the target is typedef'd to int.

                        – Antti Haapala
                        2 days ago







                      • 1





                        @AnttiHaapala: Why exactly wouldn't it be correct for an int?

                        – alk
                        2 days ago












                      • hmm... how about just using PRI16u :D

                        – Antti Haapala
                        2 days ago







                      1




                      1





                      but that's besides the problem actually, and %hu wouldn't be correct (though essentially the same representation) if the uint16_t on the target is typedef'd to int.

                      – Antti Haapala
                      2 days ago






                      but that's besides the problem actually, and %hu wouldn't be correct (though essentially the same representation) if the uint16_t on the target is typedef'd to int.

                      – Antti Haapala
                      2 days ago





                      1




                      1





                      @AnttiHaapala: Why exactly wouldn't it be correct for an int?

                      – alk
                      2 days ago






                      @AnttiHaapala: Why exactly wouldn't it be correct for an int?

                      – alk
                      2 days ago














                      hmm... how about just using PRI16u :D

                      – Antti Haapala
                      2 days ago





                      hmm... how about just using PRI16u :D

                      – Antti Haapala
                      2 days ago

















                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55450866%2fhow-can-i-force-the-size-of-an-int-for-debugging-purposes%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Sum ergo cogito? 1 nng

                      419 nièngy_Soadمي 19bal1.5o_g

                      Queiggey Chernihivv 9NnOo i Zw X QqKk LpB