diff --git a/rosidl_generator_c/resource/idl__struct.h.em b/rosidl_generator_c/resource/idl__struct.h.em index 546507f47..d45a5fb52 100644 --- a/rosidl_generator_c/resource/idl__struct.h.em +++ b/rosidl_generator_c/resource/idl__struct.h.em @@ -32,6 +32,7 @@ extern "C" { #endif +#include #include #include #include diff --git a/rosidl_generator_c/rosidl_generator_c/__init__.py b/rosidl_generator_c/rosidl_generator_c/__init__.py index 50bb60b9e..42ed3cd12 100644 --- a/rosidl_generator_c/rosidl_generator_c/__init__.py +++ b/rosidl_generator_c/rosidl_generator_c/__init__.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from math import isnan + from rosidl_generator_type_description import parse_rihs_string from rosidl_generator_type_description import RIHS01_HASH_VALUE_SIZE from rosidl_parser.definition import AbstractGenericString @@ -172,6 +174,17 @@ def value_to_c(type_, value): def basic_value_to_c(type_, value): + """ + Convert a python value into a string representing that value in C. + + Warning: The value has to be a primitive and not a list + (aka this function doesn't work for arrays) + @param type_: a ROS IDL basic type + @type type_: builtin.str + @param value: the value to convert + @type value: builtin.str + @returns: a string containing the C representation of the value + """ assert isinstance(type_, BasicType) assert value is not None @@ -209,9 +222,13 @@ def basic_value_to_c(type_, value): return f'{value}ull' if 'float' == type_.typename: + if isnan(float(value)): + return 'NAN' return f'{value}f' if 'double' == type_.typename: + if 'nan' == value: + return '(double)NAN' return f'{value}l' assert False, "unknown basic type '%s'" % type_ diff --git a/rosidl_generator_cpp/resource/idl__struct.hpp.em b/rosidl_generator_cpp/resource/idl__struct.hpp.em index c4b7c289e..8f0cfffd3 100644 --- a/rosidl_generator_cpp/resource/idl__struct.hpp.em +++ b/rosidl_generator_cpp/resource/idl__struct.hpp.em @@ -28,6 +28,7 @@ include_directives = set() #include #include +#include #include #include #include diff --git a/rosidl_generator_cpp/resource/msg__struct.hpp.em b/rosidl_generator_cpp/resource/msg__struct.hpp.em index 6e583888f..5fa4ee3f0 100644 --- a/rosidl_generator_cpp/resource/msg__struct.hpp.em +++ b/rosidl_generator_cpp/resource/msg__struct.hpp.em @@ -287,7 +287,17 @@ non_defaulted_zero_initialized_members = [ u@ @[ end if]@ @[ elif constant.type.typename == 'float']@ +@[ if constant.value == 'nan'] + std::numeric_limits::quiet_NaN()@ +@[ else]@ @(constant.value)f@ +@[ end if]@ +@[ elif constant.type.typename == 'double']@ +@[ if constant.value == 'nan'] + std::numeric_limits::quiet_NaN()@ +@[ else]@ + @(constant.value)f@ +@[ end if]@ @[ else]@ @(constant.value)@ @[ end if]; diff --git a/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py b/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py index b076fd3ed..e17dfb426 100644 --- a/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py +++ b/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py @@ -13,6 +13,7 @@ # limitations under the License. from ast import literal_eval +from math import isnan from rosidl_parser.definition import AbstractGenericString from rosidl_parser.definition import AbstractNestedType @@ -198,13 +199,18 @@ def primitive_value_to_cpp(type_, value): if type_.typename in [ 'short', 'unsigned short', 'char', 'wchar', - 'double', 'long double', 'octet', 'int8', 'uint8', 'int16', 'uint16', ]: return str(value) + if type_.typename in ['double', 'long double']: + if isnan(value): + return 'std::numeric_limits::quiet_NaN()' + else: + return str(value) + if type_.typename == 'int32': # Handle edge case for INT32_MIN # Specifically, MSVC is not happy in this case @@ -226,6 +232,8 @@ def primitive_value_to_cpp(type_, value): return '%sull' % value if type_.typename == 'float': + if isnan(value): + return 'std::numeric_limits::quiet_NaN()' return '%sf' % value assert False, "unknown primitive type '%s'" % type_.typename diff --git a/rosidl_generator_tests/CMakeLists.txt b/rosidl_generator_tests/CMakeLists.txt index b2b5d13fd..3bce7cad1 100644 --- a/rosidl_generator_tests/CMakeLists.txt +++ b/rosidl_generator_tests/CMakeLists.txt @@ -36,6 +36,7 @@ if(BUILD_TESTING) ${test_interface_files_SRV_FILES} msg/BasicIdl.idl msg/SmallConstant.msg + msg/NanTest.msg ADD_LINTER_TESTS SKIP_INSTALL ) diff --git a/rosidl_generator_tests/msg/NanTest.msg b/rosidl_generator_tests/msg/NanTest.msg new file mode 100644 index 000000000..5c441cedf --- /dev/null +++ b/rosidl_generator_tests/msg/NanTest.msg @@ -0,0 +1,4 @@ +float64 FLOAT64_NAN_UC=NAN +float64 FLOAT64_NAN_LC=nan +float32 FLOAT32_NAN_UC=NAN +float32 FLOAT32_NAN_LC=nan diff --git a/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp b/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp index 15bb4b7ef..296ac0c24 100644 --- a/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp +++ b/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp @@ -41,6 +41,7 @@ #include "rosidl_generator_tests/msg/multi_nested.hpp" #include "rosidl_generator_tests/msg/nested.hpp" #include "rosidl_generator_tests/msg/small_constant.hpp" +#include "rosidl_generator_tests/msg/nan_test.hpp" #include "rosidl_generator_tests/msg/strings.hpp" #include "rosidl_generator_tests/msg/unbounded_sequences.hpp" #include "rosidl_generator_tests/msg/w_strings.hpp" @@ -542,3 +543,16 @@ TEST(Test_messages, Test_string_array_static) { message.string_values_default.begin()); ASSERT_EQ(pattern_string_values_default, message.string_values_default); } + +TEST(Test_messages, Test_nan) { + float float_nv_uc = rosidl_generator_tests::msg::NanTest::FLOAT32_NAN_UC; + float float_nv_lc = rosidl_generator_tests::msg::NanTest::FLOAT32_NAN_UC; + double double_nv_uc = rosidl_generator_tests::msg::NanTest::FLOAT64_NAN_UC; + double double_nv_lc = rosidl_generator_tests::msg::NanTest::FLOAT64_NAN_UC; + + // nan is not equal to nan, so make sure the values are nan + EXPECT_TRUE(std::isnan(float_nv_uc)); + EXPECT_TRUE(std::isnan(float_nv_lc)); + EXPECT_TRUE(std::isnan(double_nv_uc)); + EXPECT_TRUE(std::isnan(double_nv_lc)); +}