Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

SIZEOF() on derived type

ereisch
New Contributor II
5,721 Views

Does anyone know of a way to get a compile-time sizeof() on a generic type?  Let's say I'm declaring a module that handles all operations on a derived type:

MODULE MY_MOD
  USE, INTRINSIC :: ISO_C_BINDING
  USE, INTRINSIC :: IEEE_ARITHMETIC
  TYPE, BIND(C) :: MY_MOD_TYPE
    INTEGER(KIND=C_INT32_T) :: A
    INTEGER(KIND=C_INT32_T) :: B
    INTEGER(KIND=C_INT32_T) :: C
    REAL(KIND=C_FLOAT)      :: D
  END TYPE
  INTERFACE MY_MOD_TYPE
     MODULE PROCEDURE INIT_MY_MOD_TYPE
  END INTERFACE
CONTAINS
  PURE TYPE(MY_MOD_TYPE) FUNCTION INIT_MY_MOD_TYPE() RESULT(RET)
    RET%A = -1
    RET%B = -1
    RET%C = -1
    RET%D = IEEE_VALUE( 1.0, IEEE_QUIET_NAN )
  END FUNCTION

  PURE INTEGER(KIND=C_SIZE_T) FUNCTION MY_MOD_TYPE_SIZE ()
    TYPE(MY_MOD_TYPE) :: A
    MY_MOD_TYPE_SIZE = SIZEOF(A)
  END FUNCTION
END MODULE

So, in the above, I have an initializer function for the type, and something that will return the size of the type.  However, if I'm trying to write memory-optimized code, the my_mod_type_size() function is very wasteful -- I'm declaring an entire type (which could be dozens or even hundreds of megabytes in size) to just be able to do a sizeof() on the type, and then throw away the memory after the function exits.  It appears as though it's illegal to do a sizeof(type(my_mod_type)) -- is there any way to get this (preferably at compile-time, as can be done in C) without having to declare the variable and allocate the memory for it?

0 Kudos
37 Replies
andrew_4619
Honored Contributor II
2,033 Views

totally legal! I always use:

real(dp), parameter :: pi = acos(-1.0_dp)
0 Kudos
Steve_Lionel
Honored Contributor III
2,016 Views

Constant expressions were called initialization expressions in earlier standard revisions.

Operators are described in the various sections under Expressions, broken out by numeric/logical/character/relational/defined.

0 Kudos
JohnNichols
Valued Contributor III
2,018 Views
 6.  EXPRESSIONS

          This section describes the  formation,  interpretation,
          and   evaluation   rules   for  arithmetic,  character,
          relational, and logical expressions.  An expression  is
          formed from operands, operators, and parentheses.

 

An expression is a combination of one or more operands, zero or more operators, and zero or more pairs of parentheses.

There are three kinds of expressions:

An arithmetic expression evaluates to a single arithmetic value.

A character expression evaluates to a single value of type character.

A logical or relational expression evaluates to a single logical value.

The operators indicate what action or operation to perform.

The operands indicate what items to apply the action to. An operand can be any of the following kinds of data items:

Constant

Variable

Array element

Function

Substring

Structured record field (if it evaluates to a scalar data item)

An expression

ok, I see the logical progression, I have never seen a elemental function in a parameter, that I remember.   Using the cos of pi to define -1 introduces an error at about 1 part in a billion for my pi estimate which is the number I used for years in manual design.  

 

0 Kudos
FortranFan
Honored Contributor II
1,920 Views

The term "constant expression" becomes particularly relevant in the context of a `PARAMETER` statement (or an attribute).

ANSI X3.9-1978 document (a proxy for FORTRAN 77 standard) first added `PARAMETER` statement and that document then made use of the term constant expressions ..

0 Kudos
JohnNichols
Valued Contributor III
1,907 Views

I understand using the acos for pi, it is a good idea.  I like the method @mecej4  showed me when we rewrote Magni from C# to Fortran.  The base module

 

Module Base

    INTEGER, PARAMETER :: dp = selected_real_kind(15, 307)

    INTEGER, PARAMETER :: sw = 2                    !   Output file
    INTEGER, PARAMETER :: srA = 15                  !   output.txt file
    INTEGER, PARAMETER :: srB = 16                  !   output.txt file
    INTEGER, PARAMETER :: st = 14
    INTEGER, PARAMETER :: sCAD = 12
    INTEGER, PARAMETER :: sa = 3                    !   Output file
    INTEGER, PARAMETER :: smWrite = 4
    INTEGER, PARAMETER :: si = 1
    Integer, parameter :: slog = 9                  !   Log file
    Integer, parameter :: nta = 200                  !   Log file
    Integer, parameter :: outNode = 63                  !   Log file
    Integer, parameter :: inNode = 0                  !   Log file
    integer, parameter :: nt1 = 2000
    integer, parameter :: mt1 = 2000        !   Number of members
    integer, parameter :: mn1 = 2
    integer, parameter :: ml1 = 3
    integer, parameter :: ml30 = 3000
    integer, parameter :: limit = 3

    REAL (KIND=dp), PARAMETER :: gr = 9.806_DP, pi = 3.14159265_DP  !   Standard parameters
    REAL (KIND=dp), PARAMETER :: delta = 0.001_DP                !   Error number of checking for zero
    REAL (KIND=dp), PARAMETER :: ZERO = 0.0_DP
    REAL (KIND=dp), PARAMETER :: ONE = 1.0_DP
    REAL (KIND=dp), PARAMETER :: TWO = 2.0_DP
    REAL (KIND=dp), PARAMETER :: THREE = 3.0_DP
    REAL (KIND=dp), PARAMETER :: THIRTY = 30.0_DP
    REAL (KIND=dp), PARAMETER :: FOUR = 4.0_DP
    REAL (KIND=dp), PARAMETER :: SIX = 6.0_DP
    REAL (KIND=dp), PARAMETER :: PointFIVE = 0.5_DP
    REAL (KIND=dp), PARAMETER :: PointTWOFIVE = 0.25_DP
    REAL (KIND=dp), PARAMETER :: OneHundred = 1.0_DP
    REAL (KIND=dp), PARAMETER :: DeltaFr = 15000000.0_DP
    REAL (KIND=dp), PARAMETER :: FTR = 1.0_DP
    REAL (KIND=dp), PARAMETER :: FTRA = 100.0_DP
    REAL (KIND=dp), PARAMETER :: SMALL_MASS = 0.0001_DP

    INTEGER, PARAMETER :: mn_3 = 3,mn_9 = 9, mn_2 = 2, mn_10 = 10, mn_18 = 18, mn_6 = 6, mn_12 = 12, mn_4 = 4

    contains

 

 -- it makes life very easy.   My problem is I like the 1988 Microsoft Fortran manuals and I keep them beside my desk, so they are my main Fortran read, they have great examples.

So constant expressions use the side effect from a function to set a constant.    So in lisp (setq pi (acos 0))

0 Kudos
andrew_4619
Honored Contributor II
1,902 Views

REAL (KIND=dp), PARAMETER :: OneHundred = 1.0_DP ????

Some thing just jump out of the page

 

 

0 Kudos
JohnNichols
Valued Contributor III
1,895 Views
0 Kudos
JohnNichols
Valued Contributor III
1,895 Views

Screenshot_20230205_020311.png

Complete change of topic, why cannot Intel not use 2022.2 and then 2023.1   or 2023.0  this odd numbering is to say the least annoying, it is the same as zero indexing and what day does a contract start 0 or 1, makes a difference to the contract and is the bain of contractors.  The two standard textbooks on contract scheduling one starts 0 and one starts 1 and the two people are friends.  

 

0 Kudos
Steve_Lionel
Honored Contributor III
1,868 Views

As Andrew says, in Fortran a structure constructor is just the type name. You can create a generic interface of the same name to serve as a constructor, and if so, you can export a specific procedure (which can also have the same name). Is gfortran really creating these on its own? That's weird.

If you're talking about default initialization of derived type components, there's nothing preventing a type with initialization being interoperable.

0 Kudos
ereisch
New Contributor II
1,854 Views

My point was that if I do this, as was suggested at one point:

        MODULE MY_MOD
        USE, INTRINSIC :: ISO_C_BINDING
                PUBLIC :: MY_MOD_TYPE
                TYPE, BIND(C) :: MY_MOD_TYPE
                        INTEGER(KIND=C_INT32_T) :: A = -1
                        INTEGER(KIND=C_INT32_T) :: B = -2
                        INTEGER(KIND=C_INT32_T) :: C = -3
                        REAL(KIND=C_FLOAT)      :: D = TRANSFER(Z'7FC00000', 1.0_4)
                END TYPE
        END MODULE

...the compiler does not export any functions that contain code.  I only get the following (comments and useless assembler removed for readability):

        .text
       .align    32,0x90
        .globl my_mod$
my_mod$:
        .cfi_startproc
..___tag_value_my_mod$.1:
        ret
        .align    32,0x90
        .cfi_endproc

        .type   my_mod$,@function
        .size   my_mod$,.-my_mod$
        .data
        .section .note.GNU-stack, ""

...so, you get one function defined (my_mod), but it has an empty text section.  I can create an interface called my_mod_type, and attach a procedure to it, but then that is separating the default initializers from the definitions.

Now, the interesting part -- if I create a new subroutine and USE the module I previously defined:

SUBROUTINE TEST2 (A)
  USE MY_MOD
  TYPE(MY_MOD_TYPE) :: A
  A = MY_MOD_TYPE()
END SUBROUTINE

 ...the generated code becomes:

       .align    32,0x90
        .globl test2
test2:
        .cfi_startproc
        movl      $-1, (%rdi)
        movl      $-2, 4(%rdi)
        movl      $-3, 8(%rdi)
        movl      $2143289344, 12(%rdi)
        ret
        .align    32,0x90
        .cfi_endproc
        .type   test2,@function
        .size   test2,.-test2
        .data
        .section .rodata, "a"
        .align 4
        .align 4
        .long   0x7fc00000
        .type   .L_2il0floatpacket.0,@object

Thus, the compiler is using data apparently contained in the generated *.mod file to create inlined code that populates the default values of everything in the structure, instead of calling a constructor function.  Thus, unless I'm doing something wrong, I can't call this constructor function from C.  However, my OO Fortran is very poor (I'm an F77 and C programmer, and somewhat conversant in C++....OO Fortran is very alien to me), so it's possible I'm missing a special language trick to get this constructor exported.

0 Kudos
Steve_Lionel
Honored Contributor III
1,868 Views

IEEE_VALUE is an elemental function. As it is neither an inquiry function nor transformational, it is not allowed in constant expressions.

0 Kudos
Steve_Lionel
Honored Contributor III
1,852 Views

Yes - if you have a procedure dummy argument of a derived type with initialization, the compiler gets the info from the module and does the initialization. There is no routine for this purpose, though you can write your own. Fortran doesn't give you constructors just for declaring a type.

0 Kudos
FortranFan
Honored Contributor II
1,842 Views

@ereisch ,

Please try to NOT mix concerns.  You can use the following code design principle with your threads as well:

https://en.wikipedia.org/wiki/Separation_of_concerns

Your original post was about ..

..

I'm declaring an entire type (which could be dozens or even hundreds of megabytes in size) to just be able to do a sizeof() on the type, and then throw away the memory after the function exits.  It appears as though it's illegal to do a sizeof(type(my_mod_type)) -- is there any way to get this (preferably at compile-time, as can be done in C) without having to declare the variable and allocate the memory for it?


toward which you were shown how to achieve your "sizeof" on the type at compile-time.

Then without any acknowledgement of that response, you bring up a separate concern about some "class" instantiation function unrelated to your original post.

Please strive to close out one discussion with some form of acknowledgement of the replies and then open another thread if you have other questions.

0 Kudos
ereisch
New Contributor II
1,816 Views

Well, yes, that evolved.  Someone (@FortranFan) had said it was "important" to use default initialization of components; my comment was that this was not interoperable with C.  And that answer didn't address my question anyhow, since I noted that I was looking for a solution "without having to declare the variable and allocate the memory for it".  The proposed solution of using a "mold" to declare a parameter ignored that part, since the mold still allocates the memory for the variable (albeit in the data section of the executable and not on the stack).  However, that doesn't matter since, as I noted, the memory structure in question could be hundreds of megabytes in size, so it's still consuming memory on the target computer that it'll never use.  Thus, using a "mold" would be a.) not interoperable, and b.) doesn't save the memory from being allocated for the dummy variable, just to determine the structure size.

If you don't want me pointing out an issue with your response that has nothing to do with my original question, don't post a response that has nothing to do with my original question.

That having been said, I did neglect to transcribe over the BIND(C) attributes on the INIT_MY_MOD_TYPE() function, which may have made my requirement for interoperability not as clear.  My apologies for that omission.

0 Kudos
FortranFan
Honored Contributor II
1,780 Views

@ereisch ,

Ok I'll make sure to never again reply to any of your posts following this one.  Just note what you wrote makes no sense whatsoever technically, starting with "Someone (@FortranFan) had said it was "important" to use default initialization of components; my comment was that this was not interoperable with C."  There is no connection between default initialization and interoperability with C.  Also, it is unclear what "proposed solution" is being mentioned.  What I had indicated is a named constant and it is a compile-time determination leading to a value - there is no run-time variable declaration and static or dynamic memory allocation coming into play.  The rest of the blurb is less comprehensible.


@ereisch wrote:

Well, yes, that evolved.  Someone (@FortranFan) had said it was "important" to use default initialization of components; my comment was that this was not interoperable with C.  And that answer didn't address my question anyhow, since I noted that I was looking for a solution "without having to declare the variable and allocate the memory for it".  The proposed solution of using a "mold" to declare a parameter ignored that part, since the mold still allocates the memory for the variable (albeit in the data section of the executable and not on the stack).  ..


This is for any other readers: if the intelligible concern is to be able utilize the size of an interoperable derived type in Fortran in C code, you may consider along the following lines with an "extern" object in C which is bound to a `MODULE` entity in Fortran via bind(C):

module m
   use, intrinsic :: iso_c_binding, only : c_int, c_float, c_size_t, c_sizeof
   type, bind(C) :: t
      integer(c_int) :: a = 0 
      integer(c_int) :: b = 0 
      integer(c_int) :: c = 0 
      integer(c_float) :: d = 0.0 
   end type
   integer(c_size_t), parameter :: sz_t = c_sizeof( t() )
   integer(c_size_t), bind(C, name="t_sz") :: t_sz = sz_t
end module 
#include <stdio.h>

extern size_t t_sz;

int main() {
   printf("sizeof(t): %d\n", (int)t_sz);
}
C:\temp>ifort /c /standard-semantics m.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.8.0 Build 20221119_000000
Copyright (C) 1985-2022 Intel Corporation.  All rights reserved.


C:\temp>cl /c /EHsc /W3 c.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.34.31937 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

c.c

C:\temp>link c.obj m.obj /subsystem:console /out:c.exe
Microsoft (R) Incremental Linker Version 14.34.31937.0
Copyright (C) Microsoft Corporation.  All rights reserved.


C:\temp>c.exe
sizeof(t): 16

C:\temp>

 

0 Kudos
ereisch
New Contributor II
1,807 Views

UPDATE - This seems to work, and does not allocate runtime or executable memory for the structure:

MODULE MY_MOD
  USE, INTRINSIC :: ISO_C_BINDING
  USE, INTRINSIC :: IEEE_ARITHMETIC
  REAL(KIND=C_FLOAT), PARAMETER :: SGL_NAN = TRANSFER(Z'7FC00000', 1.0_4)
  TYPE, BIND(C) :: MY_MOD_TYPE
    INTEGER(KIND=C_INT32_T) :: A = -1
    INTEGER(KIND=C_INT32_T) :: B = -1
    INTEGER(KIND=C_INT32_T) :: C = -1
    REAL(KIND=C_FLOAT)      :: D = SGL_NAN
  END TYPE
  INTEGER(KIND=C_SIZE_T), PARAMETER :: MY_MOD_TYPE_SZ = C_SIZEOF( MY_MOD_TYPE() )
CONTAINS
  PURE INTEGER(KIND=C_SIZE_T) FUNCTION MY_MOD_TYPE_SIZE () BIND(C)
    IMPLICIT NONE
    MY_MOD_TYPE_SIZE = MY_MOD_TYPE_SZ
  END FUNCTION
END MODULE MY_MOD

Thanks all for the guidance. 

0 Kudos
andrew_4619
Honored Contributor II
1,806 Views
  PURE INTEGER(KIND=C_SIZE_T) FUNCTION MY_MOD_TYPE_SIZE ()
    MY_MOD_TYPE_SIZE = 16
  END FUNCTION

 

yes but but but I would have to work it out and what if I change the DT.....

0 Kudos
Reply