Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rosidl_generator_c/resource/idl__struct.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extern "C"
{
#endif

#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
Expand Down
15 changes: 15 additions & 0 deletions rosidl_generator_c/rosidl_generator_c/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,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

Expand Down Expand Up @@ -209,9 +220,13 @@ def basic_value_to_c(type_, value):
return f'{value}ull'

if 'float' == type_.typename:
if 'nan' == value:
return 'NAN'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose to use 'nanf(\"\")' on my PR to avoid the c-style cast to a double later.

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_
Expand Down
1 change: 1 addition & 0 deletions rosidl_generator_cpp/resource/idl__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ include_directives = set()
#include <memory>
#include <string>
#include <vector>
#include <limits>

#include "rosidl_runtime_cpp/bounded_vector.hpp"
#include "rosidl_runtime_cpp/message_initialization.hpp"
Expand Down
10 changes: 10 additions & 0 deletions rosidl_generator_cpp/resource/msg__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,17 @@ non_defaulted_zero_initialized_members = [
u@
@[ end if]@
@[ elif constant.type.typename == 'float']@
@[ if constant.value == 'nan']
std::numeric_limits<float>::quiet_NaN()@
@[ else]@
@(constant.value)f@
@[ end if]@
@[ elif constant.type.typename == 'double']@
@[ if constant.value == 'nan']
std::numeric_limits<double>::quiet_NaN()@
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of coding this, I chose to use the primitive_value_to_cpp function to promote reuse.

@[ else]@
@(constant.value)f@
@[ end if]@
@[ else]@
@(constant.value)@
@[ end if];
Expand Down
10 changes: 9 additions & 1 deletion rosidl_generator_cpp/rosidl_generator_cpp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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']:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also checked if it was a float here.

if isnan(value):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason, I needed to surroudn value in a float() cast otherwise it threw.

return 'std::numeric_limits<double>::quiet_NaN()'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hard-coding as double, I used the type name here.

else:
return str(value)

if type_.typename == 'int32':
# Handle edge case for INT32_MIN
# Specifically, MSVC is not happy in this case
Expand All @@ -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<float>::quiet_NaN()'
return '%sf' % value

assert False, "unknown primitive type '%s'" % type_.typename
Expand Down
1 change: 1 addition & 0 deletions rosidl_generator_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
4 changes: 4 additions & 0 deletions rosidl_generator_tests/msg/NanTest.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
float64 FLOAT64_NAN_UC=NAN
float64 FLOAT64_NAN_LC=nan
float32 FLOAT32_NAN_UC=NAN
float32 FLOAT32_NAN_LC=nan
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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));
}