diff --git a/.gitignore b/.gitignore index 270fa634..dcc56bad 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,7 @@ /examples/generic_malloc /examples/generic_mutex /examples/macro_bits +/examples/macro_cast /examples/macro_container_of /examples/macro_packing /examples/memmap diff --git a/ChangeLog b/ChangeLog index fdb0fa18..169f8237 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-12-10 Alex Kotov + + * include/kernaux/macro.h: Macros "KERNAUX_CAST_(VAR|CONST)" have been added + 2022-12-09 Alex Kotov * include/kernaux/generic/display.h: The header has been added diff --git a/README.md b/README.md index 1bc3ba52..a3281810 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ zero). Work-in-progress APIs can change at any time. * [Feature macros](/include/kernaux/version.h.in) (*work in progress*) * [Macros](/include/kernaux/macro.h) (*non-breaking since* **0.6.0**) * [Example: packing](/examples/macro_packing.c) + * [Example: CAST\_\*](/examples/macro_cast.c); * [Example: CONTAINER_OF](/examples/macro_container_of.c) * [Example: BITS](/examples/macro_bits.c) * [Assertions](/include/kernaux/assert.h) (*non-breaking since* **0.4.0**) diff --git a/configure.ac b/configure.ac index eb3b6377..5237c021 100644 --- a/configure.ac +++ b/configure.ac @@ -331,7 +331,7 @@ AC_HEADER_STDBOOL AS_IF([test "$enable_checks" = yes -a "$ac_cv_header_stdbool_h" != yes], [AC_MSG_ERROR([the header is required])]) -AC_CHECK_HEADERS([stdarg.h stddef.h stdint.h],, +AC_CHECK_HEADERS([limits.h stdarg.h stddef.h stdint.h],, [AC_MSG_ERROR([the headers are required])]) AS_IF([test "$enable_checks" = yes], diff --git a/examples/Makefile.am b/examples/Makefile.am index b792a506..f3c6dcf8 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -53,6 +53,14 @@ TESTS += macro_bits macro_bits_LDADD = $(top_builddir)/libkernaux.la macro_bits_SOURCES = main.c macro_bits.c +############## +# macro_cast # +############## + +TESTS += macro_cast +macro_cast_LDADD = $(top_builddir)/libkernaux.la +macro_cast_SOURCES = main.c macro_cast.c + ###################### # macro_container_of # ###################### diff --git a/examples/macro_cast.c b/examples/macro_cast.c new file mode 100644 index 00000000..11023a29 --- /dev/null +++ b/examples/macro_cast.c @@ -0,0 +1,25 @@ +#include + +#include +#include + +void example_main() +{ + const uint32_t value = 123; + + // const unsigned long ul = (unsigned long)value; + KERNAUX_CAST_CONST(unsigned long, ul, value); + assert(ul == 123); + + // unsigned long long ull = (unsigned long long)value; + KERNAUX_CAST_VAR(unsigned long long, ull, value); + assert(ull == 123); + + // const [signed] long sl = ([signed] long)value; + KERNAUX_CAST_CONST(long, sl, value); + assert(sl == 123); + + // [signed] long long sll = ([signed] long long)value; + KERNAUX_CAST_VAR(long long, sll, value); + assert(sll == 123); +} diff --git a/include/kernaux/macro.h b/include/kernaux/macro.h index 9cb0c582..820c43cc 100644 --- a/include/kernaux/macro.h +++ b/include/kernaux/macro.h @@ -84,6 +84,27 @@ _kernaux_static_test_union_size_##name[ \ #define KERNAUX_BITS32(n) ((uint32_t)(((uint32_t)1) << (n))) #define KERNAUX_BITS64(n) ((uint64_t)(((uint64_t)1) << (n))) +/********************* + * Safe type casting * + *********************/ + +#define KERNAUX_CAST_VAR(type, name, value) \ + { \ + KERNAUX_UNUSED \ + static const int _kernaux_static_test_cast_pos_##name[ \ + sizeof(value) <= sizeof(type) ? 1 : -1 \ + ]; \ + KERNAUX_UNUSED \ + static const int _kernaux_static_test_cast_neg_##name[ \ + sizeof(-(value)) <= sizeof(type) ? 1 : -1 \ + ]; \ + } \ + type name = (type)(value); \ + do {} while (0) + +#define KERNAUX_CAST_CONST(type, name, value) \ + KERNAUX_CAST_VAR(const type, name, value) + #ifdef __cplusplus } #endif diff --git a/make/checks.am b/make/checks.am index 6268fd21..bfb0b861 100644 --- a/make/checks.am +++ b/make/checks.am @@ -20,6 +20,7 @@ CPPCHECK_INC = \ -I$(top_srcdir)/include CPPCHECK_SUPPRESS = \ + --suppress='constArgument:$(top_srcdir)/examples/macro_cast.c' \ --suppress='unusedStructMember:$(top_srcdir)/examples/multiboot2_header_macro.c' \ --suppress='unusedStructMember:$(top_srcdir)/tests/test_multiboot2_info_*.c' diff --git a/src/multiboot2/header_print.c b/src/multiboot2/header_print.c index 6804ae0b..bfe76c85 100644 --- a/src/multiboot2/header_print.c +++ b/src/multiboot2/header_print.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -20,14 +21,18 @@ void KernAux_Multiboot2_Header_print( KERNAUX_ASSERT(multiboot2_header); KERNAUX_ASSERT(display); + KERNAUX_CAST_CONST(unsigned long, magic, multiboot2_header->magic); + KERNAUX_CAST_CONST(unsigned long, total_size, multiboot2_header->total_size); + KERNAUX_CAST_CONST(unsigned long, checksum, multiboot2_header->checksum); + PRINTLN("Multiboot 2 header"); - PRINTLNF(" magic: %u", multiboot2_header->magic); + PRINTLNF(" magic: %lu", magic); PRINTLNF(" arch: %u (%s)", multiboot2_header->arch, KernAux_Multiboot2_Header_Arch_to_str(multiboot2_header->arch) ); - PRINTLNF(" size: %u", multiboot2_header->total_size); - PRINTLNF(" checksum: %u", multiboot2_header->checksum); + PRINTLNF(" size: %lu", total_size); + PRINTLNF(" checksum: %lu", checksum); const struct KernAux_Multiboot2_HTagBase *tag_base = (struct KernAux_Multiboot2_HTagBase*) @@ -54,15 +59,16 @@ void KernAux_Multiboot2_HTagBase_print( if (!KernAux_Multiboot2_HTagBase_is_valid(tag_base)) return; - PRINTLN("Multiboot 2 header tag"); + KERNAUX_CAST_CONST(unsigned long, flags, tag_base->flags); + KERNAUX_CAST_CONST(unsigned long, size, tag_base->size); + PRINTLN("Multiboot 2 header tag"); PRINTLNF(" type: %u (%s)", tag_base->type, KernAux_Multiboot2_HTag_to_str(tag_base->type) ); - - PRINTLNF(" flags: %u", tag_base->flags); - PRINTLNF(" size: %u", tag_base->size); + PRINTLNF(" flags: %lu", flags); + PRINTLNF(" size: %lu", size); switch (tag_base->type) { case KERNAUX_MULTIBOOT2_HTAG_NONE: diff --git a/src/multiboot2/info_print.c b/src/multiboot2/info_print.c index 1cf2a93a..7e9c4734 100644 --- a/src/multiboot2/info_print.c +++ b/src/multiboot2/info_print.c @@ -3,6 +3,7 @@ #endif #include +#include #include #include @@ -22,9 +23,12 @@ void KernAux_Multiboot2_Info_print( KERNAUX_ASSERT(multiboot2_info); KERNAUX_ASSERT(display); + KERNAUX_CAST_CONST(unsigned long, total_size, multiboot2_info->total_size); + KERNAUX_CAST_CONST(unsigned long, reserved1, multiboot2_info->reserved1); + PRINTLN("Multiboot 2 info"); - PRINTLNF(" size: %u", multiboot2_info->total_size); - PRINTLNF(" reserved1: %u", multiboot2_info->reserved1); + PRINTLNF(" size: %lu", total_size); + PRINTLNF(" reserved1: %lu", reserved1); const struct KernAux_Multiboot2_ITagBase *tag_base = (struct KernAux_Multiboot2_ITagBase*) @@ -58,7 +62,8 @@ void KernAux_Multiboot2_ITagBase_print( KernAux_Multiboot2_ITag_to_str(tag_base->type) ); - PRINTLNF(" size: %u", tag_base->size); + KERNAUX_CAST_CONST(unsigned long, size, tag_base->size); + PRINTLNF(" size: %lu", size); switch (tag_base->type) { case KERNAUX_MULTIBOOT2_ITAG_NONE: @@ -80,8 +85,11 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_Module *const tag_module = (struct KernAux_Multiboot2_ITag_Module*)tag_base; - PRINTLNF(" start: %u", tag_module->mod_start); - PRINTLNF(" end: %u", tag_module->mod_end); + KERNAUX_CAST_CONST(unsigned long, mod_start, tag_module->mod_start); + KERNAUX_CAST_CONST(unsigned long, mod_end, tag_module->mod_end); + + PRINTLNF(" start: %lu", mod_start); + PRINTLNF(" end: %lu", mod_end); PRINTLNF(" cmdline: %s", KERNAUX_MULTIBOOT2_DATA(tag_module)); } break; @@ -90,8 +98,11 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *const tag_bmi = (struct KernAux_Multiboot2_ITag_BasicMemoryInfo*)tag_base; - PRINTLNF(" mem lower: %u", tag_bmi->mem_lower); - PRINTLNF(" mem upper: %u", tag_bmi->mem_upper); + KERNAUX_CAST_CONST(unsigned long, mem_lower, tag_bmi->mem_lower); + KERNAUX_CAST_CONST(unsigned long, mem_upper, tag_bmi->mem_upper); + + PRINTLNF(" mem lower: %lu", mem_lower); + PRINTLNF(" mem upper: %lu", mem_upper); } break; case KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE: @@ -99,9 +110,13 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_BIOSBootDevice *const tag_bbd = (struct KernAux_Multiboot2_ITag_BIOSBootDevice*)tag_base; - PRINTLNF(" bios dev: %u", tag_bbd->bios_dev); - PRINTLNF(" partition: %u", tag_bbd->partition); - PRINTLNF(" sub_partition: %u", tag_bbd->sub_partition); + KERNAUX_CAST_CONST(unsigned long, bios_dev, tag_bbd->bios_dev); + KERNAUX_CAST_CONST(unsigned long, partition, tag_bbd->partition); + KERNAUX_CAST_CONST(unsigned long, sub_partition, tag_bbd->sub_partition); + + PRINTLNF(" bios dev: %lu", bios_dev); + PRINTLNF(" partition: %lu", partition); + PRINTLNF(" sub_partition: %lu", sub_partition); } break; case KERNAUX_MULTIBOOT2_ITAG_MEMORY_MAP: @@ -115,10 +130,15 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_VBEInfo *const tag_vbe = (struct KernAux_Multiboot2_ITag_VBEInfo*)tag_base; - PRINTLNF(" VBE mode: %hu", tag_vbe->vbe_mode); - PRINTLNF(" VBE interface seg: %hu", tag_vbe->vbe_interface_seg); - PRINTLNF(" VBE interface off: %hu", tag_vbe->vbe_interface_off); - PRINTLNF(" VBE interface len: %hu", tag_vbe->vbe_interface_len); + KERNAUX_CAST_CONST(unsigned long, vbe_mode, tag_vbe->vbe_mode); + KERNAUX_CAST_CONST(unsigned long, vbe_interface_seg, tag_vbe->vbe_interface_seg); + KERNAUX_CAST_CONST(unsigned long, vbe_interface_off, tag_vbe->vbe_interface_off); + KERNAUX_CAST_CONST(unsigned long, vbe_interface_len, tag_vbe->vbe_interface_len); + + PRINTLNF(" VBE mode: %lu", vbe_mode); + PRINTLNF(" VBE interface seg: %lu", vbe_interface_seg); + PRINTLNF(" VBE interface off: %lu", vbe_interface_off); + PRINTLNF(" VBE interface len: %lu", vbe_interface_len); } break; case KERNAUX_MULTIBOOT2_ITAG_FRAMEBUFFER_INFO: @@ -126,16 +146,21 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_FramebufferInfo *const tag_fb = (struct KernAux_Multiboot2_ITag_FramebufferInfo*)tag_base; - PRINTLNF( - INT_IF(" framebuffer addr: %llu", " framebuffer addr: %lu"), - tag_fb->framebuffer_addr - ); - PRINTLNF(" framebuffer pitch: %u", tag_fb->framebuffer_pitch); - PRINTLNF(" framebuffer width: %u", tag_fb->framebuffer_width); - PRINTLNF(" framebuffer height: %u", tag_fb->framebuffer_height); - PRINTLNF(" framebuffer bpp: %u", tag_fb->framebuffer_bpp); - PRINTLNF(" framebuffer type: %u", tag_fb->framebuffer_type); - PRINTLNF(" reserved1: %u", tag_fb->reserved1); + KERNAUX_CAST_CONST(unsigned long long, framebuffer_addr, tag_fb->framebuffer_addr); + KERNAUX_CAST_CONST(unsigned long, framebuffer_pitch, tag_fb->framebuffer_pitch); + KERNAUX_CAST_CONST(unsigned long, framebuffer_width, tag_fb->framebuffer_width); + KERNAUX_CAST_CONST(unsigned long, framebuffer_height, tag_fb->framebuffer_height); + KERNAUX_CAST_CONST(unsigned long, framebuffer_bpp, tag_fb->framebuffer_bpp); + KERNAUX_CAST_CONST(unsigned long, framebuffer_type, tag_fb->framebuffer_type); + KERNAUX_CAST_CONST(unsigned long, reserved1, tag_fb->reserved1); + + PRINTLNF(" framebuffer addr: %llu", framebuffer_addr); + PRINTLNF(" framebuffer pitch: %lu", framebuffer_pitch); + PRINTLNF(" framebuffer width: %lu", framebuffer_width); + PRINTLNF(" framebuffer height: %lu", framebuffer_height); + PRINTLNF(" framebuffer bpp: %lu", framebuffer_bpp); + PRINTLNF(" framebuffer type: %lu", framebuffer_type); + PRINTLNF(" reserved1: %lu", reserved1); } break; case KERNAUX_MULTIBOOT2_ITAG_ELF_SYMBOLS: @@ -149,15 +174,25 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_APMTable *const tag_apm = (struct KernAux_Multiboot2_ITag_APMTable*)tag_base; - PRINTLNF(" version: %hu", tag_apm->version); - PRINTLNF(" cseg: %hu", tag_apm->cseg); - PRINTLNF(" offset: %u", tag_apm->offset); - PRINTLNF(" cseg 16: %hu", tag_apm->cseg_16); - PRINTLNF(" dseg: %hu", tag_apm->dseg); - PRINTLNF(" flags: %hu", tag_apm->flags); - PRINTLNF(" cseg len: %hu", tag_apm->cseg_len); - PRINTLNF(" cseg 16 len: %hu", tag_apm->cseg_16_len); - PRINTLNF(" dseg len: %hu", tag_apm->dseg_len); + KERNAUX_CAST_CONST(unsigned long, version, tag_apm->version); + KERNAUX_CAST_CONST(unsigned long, cseg, tag_apm->cseg); + KERNAUX_CAST_CONST(unsigned long, offset, tag_apm->offset); + KERNAUX_CAST_CONST(unsigned long, cseg_16, tag_apm->cseg_16); + KERNAUX_CAST_CONST(unsigned long, dseg, tag_apm->dseg); + KERNAUX_CAST_CONST(unsigned long, flags, tag_apm->flags); + KERNAUX_CAST_CONST(unsigned long, cseg_len, tag_apm->cseg_len); + KERNAUX_CAST_CONST(unsigned long, cseg_16_len, tag_apm->cseg_16_len); + KERNAUX_CAST_CONST(unsigned long, dseg_len, tag_apm->dseg_len); + + PRINTLNF(" version: %lu", version); + PRINTLNF(" cseg: %lu", cseg); + PRINTLNF(" offset: %lu", offset); + PRINTLNF(" cseg 16: %lu", cseg_16); + PRINTLNF(" dseg: %lu", dseg); + PRINTLNF(" flags: %lu", flags); + PRINTLNF(" cseg len: %lu", cseg_len); + PRINTLNF(" cseg 16 len: %lu", cseg_16_len); + PRINTLNF(" dseg len: %lu", dseg_len); } break; case KERNAUX_MULTIBOOT2_ITAG_EFI_32BIT_SYSTEM_TABLE_PTR: @@ -175,16 +210,22 @@ void KernAux_Multiboot2_ITagBase_print( const struct KernAux_Multiboot2_ITag_SMBIOSTables *const tag_smbios = (struct KernAux_Multiboot2_ITag_SMBIOSTables*)tag_base; - PRINTLNF(" major: %u", tag_smbios->major); - PRINTLNF(" minor: %u", tag_smbios->minor); + KERNAUX_CAST_CONST(unsigned long, major, tag_smbios->major); + KERNAUX_CAST_CONST(unsigned long, minor, tag_smbios->minor); + KERNAUX_CAST_CONST(unsigned long, reserved0, tag_smbios->reserved1[0]); + KERNAUX_CAST_CONST(unsigned long, reserved1, tag_smbios->reserved1[1]); + KERNAUX_CAST_CONST(unsigned long, reserved2, tag_smbios->reserved1[2]); + KERNAUX_CAST_CONST(unsigned long, reserved3, tag_smbios->reserved1[3]); + KERNAUX_CAST_CONST(unsigned long, reserved4, tag_smbios->reserved1[4]); + KERNAUX_CAST_CONST(unsigned long, reserved5, tag_smbios->reserved1[5]); - PRINTLNF(" reserved1: {%u, %u, %u, %u, %u, %u}", - tag_smbios->reserved1[0], - tag_smbios->reserved1[1], - tag_smbios->reserved1[2], - tag_smbios->reserved1[3], - tag_smbios->reserved1[4], - tag_smbios->reserved1[5] + PRINTLNF(" major: %lu", major); + PRINTLNF(" minor: %lu", minor); + + PRINTLNF( + " reserved1: {%lu, %lu, %lu, %lu, %lu, %lu}", + reserved0, reserved1, reserved2, + reserved3, reserved4, reserved5 ); } break; @@ -221,10 +262,15 @@ void KernAux_Multiboot2_ITagBase_print( } break; case KERNAUX_MULTIBOOT2_ITAG_IMAGE_LOAD_BASE_PHYS_ADDR: - PRINTLNF(" load base addr: %u", - ((struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr*)tag_base)-> - load_base_addr - ); + { + KERNAUX_CAST_CONST( + unsigned long, + load_base_addr, + ((struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr*) + tag_base)->load_base_addr + ); + PRINTLNF(" load base addr: %lu", load_base_addr); + } break; } } @@ -271,8 +317,11 @@ void KernAux_Multiboot2_ITag_MemoryMap_print( return; } - PRINTLNF(" entry size: %u", tag->entry_size); - PRINTLNF(" entry version: %u", tag->entry_version); + KERNAUX_CAST_CONST(unsigned long, entry_size, tag->entry_size); + KERNAUX_CAST_CONST(unsigned long, entry_version, tag->entry_version); + + PRINTLNF(" entry size: %lu", entry_size); + PRINTLNF(" entry version: %lu", entry_version); PRINTLN(" entries:"); const struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase *const entries = @@ -284,17 +333,16 @@ void KernAux_Multiboot2_ITag_MemoryMap_print( index < (tag->base.size - sizeof(*tag)) / tag->entry_size; ++index ) { - PRINTLNF(INT_IF(" entry %u", " entry %lu"), index); - PRINTLNF( - INT_IF(" base addr: %llu", " base addr: %lu"), - entries[index].base_addr - ); - PRINTLNF( - INT_IF(" length: %llu", " length: %lu"), - entries[index].length - ); - PRINTLNF(" type: %u", entries[index].type); - PRINTLNF(" reserved1: %u", entries[index].reserved1); + KERNAUX_CAST_CONST(unsigned long long, base_addr, entries[index].base_addr); + KERNAUX_CAST_CONST(unsigned long long, length, entries[index].length); + KERNAUX_CAST_CONST(unsigned long, type, entries[index].type); + KERNAUX_CAST_CONST(unsigned long, reserved1, entries[index].reserved1); + + PRINTLNF(" entry %zu", index); + PRINTLNF(" base addr: %llu", base_addr); + PRINTLNF(" length: %llu", length); + PRINTLNF(" type: %lu", type); + PRINTLNF(" reserved1: %lu", reserved1); } } @@ -310,10 +358,15 @@ void KernAux_Multiboot2_ITag_ELFSymbols_print( return; } - PRINTLNF(" num: %hu", tag->num); - PRINTLNF(" entsize: %hu", tag->ent_size); - PRINTLNF(" shndx: %hu", tag->shndx); - PRINTLNF(" reserved1: %hu", tag->reserved1); + KERNAUX_CAST_CONST(unsigned long, num, tag->num); + KERNAUX_CAST_CONST(unsigned long, ent_size, tag->ent_size); + KERNAUX_CAST_CONST(unsigned long, shndx, tag->shndx); + KERNAUX_CAST_CONST(unsigned long, reserved1, tag->reserved1); + + PRINTLNF(" num: %lu", num); + PRINTLNF(" entsize: %lu", ent_size); + PRINTLNF(" shndx: %lu", shndx); + PRINTLNF(" reserved1: %lu", reserved1); // TODO: implement this }