Skip to content

Commit 2f9032c

Browse files
authored
Merge pull request #173 from mutouyun/issue-171
fix(win): fix MinGW compilation failure with std::hex/std::dec (issue #171)
2 parents 46be39b + 642be36 commit 2f9032c

File tree

3 files changed

+74
-3
lines changed

3 files changed

+74
-3
lines changed

src/libipc/platform/win/mutex.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class mutex {
7575
}
7676
break; // loop again
7777
default:
78-
log.error("fail WaitForSingleObject[", ::GetLastError(), "]: 0x", std::hex, ret, std::dec);
78+
log.error("fail WaitForSingleObject[", ::GetLastError(), "]: ", ipc::spec("#x")(ret));
7979
return false;
8080
}
8181
}
@@ -93,7 +93,7 @@ class mutex {
9393
unlock();
9494
LIBIPC_FALLTHROUGH;
9595
default:
96-
log.error("fail WaitForSingleObject[", ::GetLastError(), "]: 0x", std::hex, ret, std::dec);
96+
log.error("fail WaitForSingleObject[", ::GetLastError(), "]: ", ipc::spec("#x")(ret));
9797
throw std::system_error{static_cast<int>(ret), std::system_category()};
9898
}
9999
}

src/libipc/platform/win/semaphore.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class semaphore {
6868
return false;
6969
case WAIT_ABANDONED:
7070
default:
71-
log.error("fail WaitForSingleObject[", ::GetLastError(), "]: 0x", std::hex, ret, std::dec);
71+
log.error("fail WaitForSingleObject[", ::GetLastError(), "]: ", ipc::spec("#x")(ret));
7272
return false;
7373
}
7474
}

test/imp/test_imp_fmt.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,74 @@ TEST(fmt, result) {
191191
EXPECT_EQ(ipc::fmt(r1), ipc::fmt("succ, error = ", std::error_code()));
192192
}
193193
}
194+
195+
/// \brief Test case for issue #171: Compiler failures under MinGW
196+
/// \see https://github.com/mutouyun/cpp-ipc/issues/171
197+
///
198+
/// The issue is that std::hex and std::dec (I/O manipulators) were incorrectly
199+
/// used with ipc::fmt. These are function pointers of type:
200+
/// std::ios_base& (*)(std::ios_base&)
201+
/// which ipc::fmt does not support.
202+
///
203+
/// The correct way to output hexadecimal values with ipc::fmt is to use ipc::spec.
204+
TEST(fmt, hex_output_with_spec) {
205+
/// \brief Basic hexadecimal formatting using ipc::spec
206+
/// This is the correct way to format hex values (instead of std::hex)
207+
{
208+
unsigned int val = 255;
209+
EXPECT_EQ(ipc::fmt(ipc::spec("x")(val)), "ff");
210+
EXPECT_EQ(ipc::fmt(ipc::spec("X")(val)), "FF");
211+
EXPECT_EQ(ipc::fmt(ipc::spec("08x")(val)), "000000ff");
212+
EXPECT_EQ(ipc::fmt(ipc::spec("08X")(val)), "000000FF");
213+
}
214+
215+
/// \brief Hex formatting with prefix (simulating "0x" prefix like std::hex would produce)
216+
{
217+
unsigned int val = 0xDEADBEEF;
218+
// Correct way: use string concatenation with ipc::spec for hex format
219+
EXPECT_EQ(ipc::fmt("0x", ipc::spec("x")(val)), "0xdeadbeef");
220+
EXPECT_EQ(ipc::fmt("0x", ipc::spec("X")(val)), "0xDEADBEEF");
221+
EXPECT_EQ(ipc::fmt("0x", ipc::spec("08x")(val)), "0xdeadbeef");
222+
}
223+
224+
/// \brief Mixed decimal and hex output (simulating the problematic log pattern from issue #171)
225+
/// Original problematic code pattern was:
226+
/// log.error("fail WaitForSingleObject[", ::GetLastError(), "]: 0x", std::hex, ret, std::dec);
227+
/// Correct pattern should be:
228+
/// log.error("fail WaitForSingleObject[", ::GetLastError(), "]: ", ipc::spec("08x")(ret));
229+
{
230+
unsigned long error_code = 5; // ERROR_ACCESS_DENIED
231+
unsigned int ret = 0x00000102; // WAIT_TIMEOUT value
232+
233+
// Correct way to format the log message
234+
auto msg = ipc::fmt("fail WaitForSingleObject[", error_code, "]: ", ipc::spec("08x")(ret));
235+
EXPECT_EQ(msg, "fail WaitForSingleObject[5]: 00000102");
236+
237+
// Alternative with "0x" prefix
238+
auto msg2 = ipc::fmt("fail WaitForSingleObject[", error_code, "]: 0x", ipc::spec("x")(ret));
239+
EXPECT_EQ(msg2, "fail WaitForSingleObject[5]: 0x102");
240+
}
241+
242+
/// \brief Various integer types with hex formatting
243+
/// Note: ipc::spec format string should NOT include length modifiers (like "ll").
244+
/// The to_string function automatically adds the correct length modifier based on
245+
/// the argument type. Just use "x" or "X" for hex conversion.
246+
{
247+
EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned char)0xAB)), "ab");
248+
EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned short)0xABCD)), "abcd");
249+
EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned int)0xABCDEF01)), "abcdef01");
250+
EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned long)0xABCDEF01)), "abcdef01");
251+
// For unsigned long long, just use "x" - the length modifier is added automatically
252+
EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned long long)0xABCDEF0123456789ULL)), "abcdef0123456789");
253+
}
254+
255+
/// \brief Width and padding with hex
256+
{
257+
unsigned int val = 0x1F;
258+
EXPECT_EQ(ipc::fmt(ipc::spec("2x")(val)), "1f");
259+
EXPECT_EQ(ipc::fmt(ipc::spec("4x")(val)), " 1f");
260+
EXPECT_EQ(ipc::fmt(ipc::spec("04x")(val)), "001f");
261+
EXPECT_EQ(ipc::fmt(ipc::spec("8x")(val)), " 1f");
262+
EXPECT_EQ(ipc::fmt(ipc::spec("08x")(val)), "0000001f");
263+
}
264+
}

0 commit comments

Comments
 (0)