1

I need to hide a single field, not several, inside a structure:

struct MyType1
{
   unsigned char Value;
}; //

struct MyType2
{
   unsigned void* Value;
} ; //

struct MyType3
{
  signed int;
} ; //

What I want is to have the struct type to have the same size, if possible, that the primitive type variables, but that the compiler treated it like a new type.

In some part of the code I want to cast back the structures, to the simple value.

And also create arrays with this struct type but, with little space.

MyType1 MyArray[255];

I already check previous answers, but, didn't find it.

Example:

typedef
   unsigned int /* rename as */ mydatetime;

// Define new type as
struct mydatetimetype
{
  unsigned int /* field */ value;
} ;

Let's suppose I have these functions in the the same program, but different include files :

void SomeFunc ( unsigned int /* param */ anyparam );

void SomeFunc ( mydatetime /* param */ anyparam );

void SomeFunc ( mydatetimetype /* param */ anyparam );

My programming editor or I.D.E. confuses the first two functions.

In some part of the code, later, I will use the packed type with integer operations, but I should be hidden from other programmers, that use this type.

Note that, I also want to apply this feature to other types like pointers or characters.

And, "forwarding" or using an "opaque" structure is not necessary.

How does a single field structure gets padded or packed ?

Should I add an attribute to pack or pad this structure for better performance ?

Is there already a name for this trick ?

umlcat
  • 4,091
  • 3
  • 19
  • 29
  • 2
    This is entirely implementation-dependent. The technique you're looking for is commonly called "strong typedef". – Quentin Aug 02 '19 at 12:07
  • 12
    ***Why*** do you need to "hide a single item ... inside a structure"? What is the actual problem you need to solve? – Some programmer dude Aug 02 '19 at 12:07
  • 2
    I am just curious, why do you want to hide the variable in a `struct`? – jpnadas Aug 02 '19 at 12:07
  • There is no guarantee, in a portable sense, that the compiler will not pad that struct to a larger size. – Tanveer Badar Aug 02 '19 at 12:27
  • 3
    Why don't you try to use a union? – Sir Jo Black Aug 02 '19 at 12:28
  • @some programmer dude : As I already write in the post, I have several programs where I need to use a simple type as a different type. – umlcat Aug 02 '19 at 12:36
  • Please clarify your question. It's unclear if you have actually any problem with the padding. You haven't shown any numbers. – user694733 Aug 02 '19 at 12:42
  • 1
    Is MSVC your IDE? In the last example you are showing two functions with the same signature and an *overloaded* one. – Bob__ Aug 02 '19 at 13:21
  • @Bob__3 No, but I still want the enclosed type, to be treated as different type and still have the same performance. – umlcat Aug 02 '19 at 13:28
  • Consider that for a C compiler the declaration of a function doesn't generates type dependent naming in the object (C++ does). That means the linker may generate a duplicate definition error if the functions are public in the same module or are external. – Sir Jo Black Aug 02 '19 at 13:49
  • 1
    If you are going to enforce such strongly typed style, but still plan to use the same name for functions accepting different types, consider using C11 `_Generic`: https://wandbox.org/permlink/RYNSgEg0LlkdqSCc – Bob__ Aug 02 '19 at 14:26

2 Answers2

1

I hope that the code below may help you.

The code show you how you may use union to obtain that more type uses the same memory space.

The result of this code might be implemantation dependent, anyway it demonstraits you that all the types specified into the integers union share the same memory space.

A variable declared as integers (in the code is k) is always long as the longer type into the declaration. Then we have that, in the code, the variable k may contains integer types from 8 bits to 64 bits using always 64 bits.

Although I only used integer types, the type you may use inside union declarations may be of whatever type you want also struct types and/or pointers.

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

typedef union integers {
    int8_t i8;
    int16_t i16;
    int32_t i32;
    int64_t i64;
    } integers;

typedef struct sInt {
    integers a;
    integers b;
} sInt;

int main(void) {
    integers k;
    sInt s;

    k.i64=0x1011121314151617;

    printf("Int 08: %" PRIx8 "h\n", k.i8 );
    printf("Int 16: %" PRIx16 "h\n", k.i16 );
    printf("Int 32: %" PRIx32 "h\n", k.i32 );
    printf("Int 64: %" PRIx64 "h\n", k.i64 );

    s.a.i64=0x1011121314151617;
    s.b.i64=0x0102030405060708;

    printf("Int a.08: %" PRIx8 "h\n", s.a.i8 );
    printf("Int a.16: %" PRIx16 "h\n", s.a.i16 );
    printf("Int a.32: %" PRIx32 "h\n", s.a.i32 );
    printf("Int a.64: %" PRIx64 "h\n", s.a.i64 );

    printf("Int b.08: %" PRIx8 "h\n", s.b.i8 );
    printf("Int b.16: %" PRIx16 "h\n", s.b.i16 );
    printf("Int b.32: %" PRIx32 "h\n", s.b.i32 );
    printf("Int b.64: %" PRIx64 "h\n", s.b.i64 );

    return 0;
}

Note: If your problem is the padding into the structure this code is not entirely the answer you're searching for. To manage padding you have to use #pragma pack() (gcc and other compilers manage #pragmas)

Sir Jo Black
  • 2,024
  • 2
  • 15
  • 22
  • Thanks, I will run the code, later, looks very detailed. – umlcat Aug 02 '19 at 13:33
  • Thanks. But, in this case, I require to have the single field, independent from other variables. – umlcat Aug 02 '19 at 13:35
  • Are you saying that you need to use `k` and not `k.i8` or `k.i16`? – Sir Jo Black Aug 02 '19 at 13:42
  • 2
    "*To manage padding you have to use `#pragma push()` and `#pragma pop`*" you seem to be confusing this with [`pack(n) ` and `pack()`](https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html)? – alk Aug 02 '19 at 14:58
  • Excuse me for the refuse. I edited. I confused with the syntax of pack. – Sir Jo Black Aug 02 '19 at 20:21
  • @Sir Jo Black : I declare struct datetime { int value } x; but later use SomeFunc ((int) x) – umlcat Aug 03 '19 at 14:32
  • You cannot cast `struct x` as `int`, it generate an error (error: operand of type 'struct datetime' where arithmetic or pointer type is required). Why don't you call `SomeFunc(x.value);`? – Sir Jo Black Aug 04 '19 at 09:27
0

Structs can be padded to align address boundaries. So your first and third struct more likely will not have the same size as primitive types.

Single-field structs more likely be padded "behind" the field, but C standard does not state how compiler should carry this out.

You should add attribute if you want cast your structure to primitive type (to be sure you are casting value it stores and not garbage in padding) but, i think (and do not recommend) possible to cast structure to variable and get correct result even without attributes (though it is very implementation dependent). But you will get small performance penalty for every processor attempt to load non-aligned structure from memory.

Also you should be careful, because packing structs may be dangerous

  • 1
    *"So your first and third struct more likely will not have the same size as primitive types."* Do you have an example of a modern implementation that actually does this? Alignment restrictions of complete structs are dictated by their members, and in typical modern implementation the struct with single member should not have any reason to add padding. – user694733 Aug 02 '19 at 12:39
  • @user694733 Yeah, you right, none of modern compilers do that. I [tested](https://godbolt.org/z/BUj8xM). – nonForgivingJesus Aug 02 '19 at 13:15
  • 1
    For completeness: The C standard guarantees that there never will be any padding *before* a `struct`'s 1st element. – alk Aug 02 '19 at 15:02